Skip to content

ci: security static analysis (Sobelow, CodeQL) and dependency scanning - #15

Merged
HackTuah merged 6 commits into
mainfrom
silver/sast
Oct 6, 2026
Merged

HackTuah merged 6 commits into
mainfrom
silver/sast

Conversation

@HackTuah

@HackTuah HackTuah commented Oct 6, 2026

Copy link
Copy Markdown
Member

What

Security static analysis and dependency scanning in CI. This is for silver static_analysis_common_vulnerabilities and Baseline osps_vm_05_01/05_02/05_03 and osps_vm_06_01/06_02.

  • Sobelow 0.16 (dev/test only) runs in the server job on Elixir 1.19, with any finding failing the build.
    • Config: server/.sobelow-conf. It uses router: :none, Sobelow's mode for plain Plug apps: the Phoenix-only CSRF/CSP/header checks are skipped, and every injection, traversal and deserialization check still runs.
    • One real hardening fix: the lookup cache now reads rows with Plug.Crypto.non_executable_binary_to_term/2. A regression test plants a function in a cache row and expects a miss; it fails without the fix. Only the server writes that column, so this wasn't exploitable.
    • 23 low-confidence path findings are false positives: paths from the server's own settings or an operator's command line, never a request. Each one is skipped per function with a written reason.
  • CodeQL (codeql.yml): actions and javascript-typescript, security-extended queries, on PRs, pushes to main and weekly. Pinned by SHA, with minimal permissions.
  • OSV-Scanner 2.6.0 (dependency-scan.yml, the binary checked against its SHA-256) scans all three lockfiles on PRs, pushes and weekly.
    • The release workflow runs it before building, and no release is built if it fails.
    • Accepted exceptions go in osv-scanner.toml, each with a reason and an expiry date.
  • Dependabot now covers site/.
  • Policy: docs/security/dependency-and-static-analysis-policy.md, linked from SECURITY.md and CONTRIBUTING.md. It covers severities, what blocks a merge or a release, fix deadlines, how an unreachable finding is accepted, and a dependency license list.

For the maintainer

  • Confirm the license list in the policy. None existed, and Baseline VM-05.01 asks for one:
    • runtime dependencies: Apache-2.0, MIT, BSD-2/3, ISC, 0BSD, Zlib, Unicode-3.0, CC0 or public domain;
    • dev tools: any OSI license.
  • After merging, add osv-scanner and CodeQL (a "Require code scanning results" rule, or the analyze (…) checks) to the main ruleset's required checks.
  • Locally, an old global sobelow-0.15.0 mix archive shadows the project's 0.16; mix archive.uninstall sobelow removes it.

Checked

  • JavaScript and repo checks: npm run lint, npm test (1873), check-versions and reuse lint pass.
  • Server: mix format, compile --warnings-as-errors, credo, hex.audit, deps.audit and deps.unlock --check-unused pass. mix test: 1001 tests, 0 failures. mix sobelow exits 0, and planted findings make it exit 1.
  • Scanners and workflows: OSV-Scanner on the three lockfiles is clean. Every workflow passes actionlint 1.7.12. CodeQL can't run locally; it runs on this PR.
  • Combined with PR feat(server): secrets from files, XDG folders and an uninstall #13: Sobelow found one new path read (the *_FILE secrets). PR feat(server): secrets from files, XDG folders and an uninstall #13 now carries its justified skip, and the combined tree scans clean.

🤖 Generated with Claude Code

Ayla Croft and others added 6 commits October 6, 2026 15:56
The lookup cache keeps each model answer as an Erlang term in the
server's own database. Reading it back used binary_to_term with :safe,
which stops new atoms but still accepts a function. A row changed on
disk could then hand the server a function as part of an answer.

The cache now reads entries with Plug.Crypto.non_executable_binary_to_term
(and :safe), so such a row is a cache miss. plug_crypto already came
with plug; it is now a direct dependency because the server calls it.
A regression test plants a function in a cache row and expects a miss.

Found by Sobelow (Misc.BinToTerm, high confidence). Nothing from the
network reaches this call, so it was hardening, not an exploitable bug.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ayla Croft <dev@scriptkittyos.com>
Sobelow is a security analyser for Elixir. It looks for SQL and command
injection, path traversal, unsafe binary_to_term, atom exhaustion and
insecure settings. It now runs in CI's server job (newest Elixir) and
fails on any finding, at any confidence.

Kotiko is a plain Plug app, so server/.sobelow-conf sets router: :none:
the Phoenix router checks have nothing to read, and the other checks
still run. It also scans the mix tasks, migrations and scripts, fails if
a file can't be parsed, and makes no network requests.

The first scan found one real issue, fixed in the previous commit, and
23 low-confidence path traversal findings in 17 functions. Every one is
a file call whose path comes from the server's own settings (the data
folder, the token file, backups, the model list cache) or from an
operator's command line (mix kotiko.import, mix kotiko.export, the .env
file). None takes a path from a request. Each of those functions now
carries a sobelow_skip comment under a line saying why, so a new file
call anywhere else still fails CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ayla Croft <dev@scriptkittyos.com>
OSV-Scanner checks the three lockfiles (the dev tools, the docs site and
the server's mix.lock) against the OSV database, which also lists
malicious packages. It runs on every pull request and push to main,
every Monday, and from the release workflow: a release isn't built when
the scan fails. Any known vulnerability fails it, at any severity,
unless osv-scanner.toml accepts it with a reason and an expiry date.

OSV-Scanner over npm audit: one tool covers both npm lockfiles and
mix.lock, it needs no node_modules, and accepted findings expire on
their own. The dependency review action only sees what a pull request
changes, so it can't check a release. The binary is a pinned release
checked against its SHA-256, like gitleaks.

The scan is a reusable workflow, so the release runs the same check
with the same pin. mix deps.audit and mix hex.audit stay in CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ayla Croft <dev@scriptkittyos.com>
The site has its own package.json and lockfile in site/, which
Dependabot didn't watch. It now opens weekly updates for them, grouped
like the others.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ayla Croft <dev@scriptkittyos.com>
CodeQL, GitHub's security analyser, now checks the JavaScript (the
extension, scripts, tests and docs site) and the GitHub Actions
workflows (script injection, untrusted checkouts, token permissions)
with the security-extended queries. It runs on every pull request and
push to main, and every Monday. Results go to the Security tab and the
"Code scanning results" check.

Both languages are analysed from source, so there is nothing to build.
The action is pinned by commit SHA.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ayla Croft <dev@scriptkittyos.com>
What the dependency scans and the security analysers check, what blocks
a merge or a release, how fast a finding is fixed (the same targets as
a reported vulnerability), how a finding that can't be exploited is
accepted and where that is recorded, and the licenses a runtime
dependency may have. SECURITY.md and CONTRIBUTING.md link to it.

The assurance case now names OSV-Scanner and Sobelow, and the lookup
cache's safer decoding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ayla Croft <dev@scriptkittyos.com>
@HackTuah
HackTuah requested a review from a team as a code owner October 6, 2026 19:59
@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@HackTuah
HackTuah merged commit 8126dd5 into main Oct 6, 2026
14 checks passed
@HackTuah
HackTuah deleted the silver/sast branch October 6, 2026 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants