SPHIOR CODE

Deterministic security findings and fix guidance for your AI agent. Runs locally, no account needed.

ドキュメント

SPHIOR CODE

Deterministic security scanning for source code — hard-coded secrets, insecure patterns mapped to CWE, and data-flow (taint) analysis — in your terminal, CI, VS Code, JetBrains IDEs and AI coding assistants. It runs entirely on your machine.

No AI in detection. No source upload. No telemetry. No account. The same code always produces the same findings.

npm MCP server VS Code Marketplace Open VSX JetBrains Plugin License: MIT


Contents


Try it in 10 seconds

No install, no account, no config. Requires Node.js 18+.

npx @sphior/scan run .

In a terminal you get a table sorted by severity:

  critical app.js:4   Stripe Live Secret Key (CWE-798)
  critical app.js:6   SQL injection (untrusted input → query) (CWE-89)
  critical app.js:9   Command injection (untrusted input → shell) (CWE-78)
  high     app.js:12  XSS (untrusted input → HTML sink) (CWE-79)
  high     util.py:3  Unsafe pickle deserialization (CWE-502)
  high     util.py:5  TLS verification disabled (verify=False) (CWE-295)
  medium   util.py:2  Weak hash algorithm (CWE-327)

SPHIOR CODE: 9 findings (critical=3 high=5 medium=1 low=0) 3 files scanned engine=0.1.0 ruleset=2026.10.23-24

Piped, the same command prints SARIF instead, so npx @sphior/scan run . | jq works.

Then hand the findings to the AI assistant you already use:

claude mcp add sphior-code -- npx -y sphior-code-mcp

and ask it: "Scan this project and fix the critical issues."


Where you can use it

One detection engine, several ways in. Everything in this table runs locally and needs no account.

SurfacePackageWhat you get
Command line@sphior/scanScan a directory. Table, SARIF, JSON or AI fix context. Fails the build by severity.
CI@sphior/scanSARIF for GitHub code scanning and most CI dashboards. --fail-on gate.
GitHub ActionsToraastrta/sphior-scan-actionOne step: scan, job summary, Security tab, fail-on gate.
pre-commithook in this repositoryScan before every commit and stop it on serious findings.
VS Code (and Cursor, Windsurf, VSCodium)sphior.sphior-code · Open VSXFindings as you type. A quick fix that hands the finding to your AI.
JetBrains IDEsplugin 33696The same in IntelliJ IDEA, PyCharm, WebStorm, GoLand, Rider, PhpStorm, RubyMine, CLion and others.
Zedpackages/sphior-zedFindings as you type, and the MCP server for Zed's agent. Two extensions.
AI coding assistantssphior-code-mcpAn MCP server. Your assistant scans the workspace and receives the location and the remediation for each finding.
Agent skillsplugin/skillsFour skills — fix, triage, set up CI, pre-release gate — for Claude Code, Codex, Cursor, GitHub Copilot and claude.ai.
Claude Codeplugin in this repositoryAll four skills in one install; add the MCP server with one command.
Cursorplugin in this repositoryThe same plugin for Cursor's agent: the MCP server and all four skills.

What it detects

Ruleset 2026.10.23-24, the version shipped in @sphior/scan 0.1.7 and later, sphior-code-mcp 1.1.9 and later, and the VS Code extension 0.1.3 and later.

1. Hard-coded secrets — 36 rules

Provider-specific signatures plus one generic high-entropy rule.

ProvidersAWS · Anthropic · OpenAI · GitHub · GitLab · Google · Stripe (live and test) · Slack · Twilio · SendGrid · Mailchimp · Shopify · Square · DigitalOcean · Discord · Databricks · Linear · Postman · HashiCorp Vault · Grafana · Sentry · npm · PyPI · Doppler · Terraform Cloud · New Relic · SonarQube · Figma · Telegram · JWT · PEM private keys
Generic ruleA quoted value of 16+ characters assigned to a name such as secret, token, password, api_key or credential, with Shannon entropy ≥ 3.5 bits/char. Reported as needs_review.
Noise controlPublished documentation examples, placeholders (your…, example, xxxx, <…>) and repeated-character values are not reported. A PEM header on its own is not reported as a private key.
What is keptNever the value. A masked preview (sk_…Pq) and a SHA-256 of the match. The fingerprint is built from rule + path + that hash, so it survives line shifts.
MappingCWE-798 · OWASP A07:2021

Secrets are searched in every text file, not only source files. .env*, .github/ and *.example files are deliberately scanned, because real keys end up there.

2. Insecure code patterns — 84 rules

Rules for constructs that are dangerous on their own, each mapped to a CWE and an OWASP Top 10 (2021) category.

LanguageRulesLanguageRules
Python19Ruby6
Java12Go5
JavaScript / TypeScript12C#4
PHP8Kotlin4
C / C++3Rust3
SQL3Swift3
Scala2

Covered weaknesses include OS command injection (CWE-78), SQL injection (CWE-89), code injection and eval (CWE-94/95), XSS sinks (CWE-79), path traversal (CWE-22), SSRF (CWE-918), unsafe deserialization (CWE-502), disabled TLS verification (CWE-295), weak hashes and ciphers (CWE-327), insecure randomness (CWE-330), cookies without Secure (CWE-614), XXE (CWE-611), LDAP / XPath / NoSQL injection (CWE-90 / 643 / 943), file inclusion (CWE-98), open redirect (CWE-601), header injection (CWE-113), prototype pollution (CWE-1321), format strings (CWE-134) and buffer overflows (CWE-120).

3. Data-flow (taint) analysis — 69 rules across 13 languages

Tracks untrusted input from where it enters to where it is used, so db.query("… " + req.query.id) is reported as SQL injection, not as a generic string concatenation. Flows are followed through local variables and across functions in the same file, including calls more than one level deep.

LanguageParserSinks
JavaScript / TypeScriptBabel ASTcommand · code (eval, vm, new Function, dynamic require) · SQL · XSS · SSRF · path traversal · open redirect · NoSQL · header injection · prototype pollution
Pythontree-sittercode · command · SQL · SSRF · template injection · XSS · deserialization · NoSQL · XXE · XPath · LDAP · path traversal
PHPtree-sittercommand · code · SQL · file inclusion · path traversal · XSS
Rubytree-sittercommand · code · SQL · SSRF · path traversal · XSS
C#tree-sittercommand · SQL · SSRF · path traversal · XSS
Go · Java · Kotlin · Scalatree-sittercommand · SQL · SSRF · path traversal
C · C++tree-sittercommand · path traversal · format string · buffer overflow
Rust · Swifttree-sittercommand · path traversal · SSRF

Typical sources: req.query / req.body / req.params / req.headers / req.cookies, location.*, document.cookie, URLSearchParams.get and FormData.get in JavaScript; request.args / request.form / request.GET in Python; $_GET / $_POST in PHP; params in Ruby; getParameter in Java; FormValue / URL.Query() in Go; argv / getenv in C.

Taint findings are reported with confidence likely. A pattern rule and a taint rule can fire on the same line; the AI fix context groups them into one place to fix.

Languages and parsing

Languages
Parsed with a real grammarJavaScript, TypeScript, JSX, TSX (.js .jsx .ts .tsx .mjs .cjs) · Python · Go · PHP · Ruby · Java · C# · Rust · Kotlin · C · C++ · Scala · Swift
Pattern rules onlySQL files

Grammars are bundled as WebAssembly, so nothing is downloaded at run time. If a file cannot be parsed, the scan falls back to the pattern rules for that file instead of skipping it.

Detection is regression-gated against a fixed corpus: a rule change that loses a detection, or that starts firing on a known-safe variant, fails the build rather than shipping.


What a finding looks like

--json out.json writes an array of findings. Keys are sorted and the order is stable (path → line → column → kind → rule), so two runs on the same code produce byte-identical files.

{
  "rule_id": "secret.stripe.live",
  "kind": "sast_secret",
  "title": "Stripe Live Secret Key",
  "severity": "critical",
  "confidence": "confirmed",
  "cwe": "CWE-798",
  "owasp": "A07:2021",
  "provider": "Stripe",
  "masked": "sk_…Pq",
  "location": { "path": "app.js", "start_line": 4, "start_col": 21, "end_line": 4, "end_col": 73 },
  "message": "Stripe secret detected in source. Rotate it and move to a secrets manager / environment variable.",
  "remediation": "Revoke/rotate the exposed credential immediately, remove it from source (and Git history), and load it from a secrets manager or environment variable at runtime.",
  "references": ["https://cwe.mitre.org/data/definitions/798.html"],
  "fingerprint": "4b8f19ea…6e89",
  "snippet_hash": "fab5c9c9…96c7",
  "schema_version": 1
}
FieldValues
severitycritical · high · medium · low · info
confidenceconfirmed (the construct itself is the problem) · likely · needs_review
kindsast_secret · sast_pattern
fingerprintSHA-256. Stable across runs and machines, used to track the same finding over time.

Command line

npx @sphior/scan run <dir> [options]

# or install it
npm install -g @sphior/scan
sphior-scan run <dir> [options]
OptionWhat it does
--sarif <file>Write SARIF 2.1.0. Accepted by GitHub code scanning and most CI dashboards.
--json <file>Write the findings as JSON.
--fix-context <file>Write one entry per place to fix, with remediation steps and instructions for an AI agent. Source code is not included.
--suppressed <file>Write the findings you accepted through .sphiorignore or inline comments, with the reason.
--fail-on <severity>Exit 1 if any finding is at or above critical, high, medium, low or info.
--no-ignore-fileIgnore .sphiorignore for this run.

Options accept --option value and --option=value; --fail-on is case-insensitive. From 0.1.8 a mistyped option or threshold stops the run with exit 2 and says why, so a typo in CI can never quietly turn the gate off.

Output. With none of --sarif, --json or --fix-context, results go to standard output: a table when it is a terminal, SARIF when it is piped or redirected. A one-line summary with the engine and ruleset versions is always written to standard error.

Exit codes.

CodeMeaning
0Scan completed, and nothing reached the --fail-on threshold (or no threshold was given).
1At least one finding at or above --fail-on.
2Nothing was scanned: the directory does not exist, or an option is unknown or has an invalid value. Never reported as a clean result.

A directory with no scannable files is reported as such, with a warning, instead of as "0 findings".

What is read. Text files up to 512 KB. Files with a NUL byte in the first 8 KB are treated as binary and skipped. Build output and fetched dependencies are skipped by directory name: node_modules, dist, build, out, coverage, .next, .nuxt, .svelte-kit, .vercel, .venv, venv, __pycache__, target, .gradle, vendor, Pods, .terraform, .git and similar. .gitignore is not read.


CI and GitHub code scanning

# .github/workflows/sphior-code.yml
name: SPHIOR CODE
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write   # only needed for the upload step
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npx -y @sphior/scan@0.1.8 run . --sarif sphior.sarif --fail-on high
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: sphior.sarif
  • Pin the version (@sphior/scan@0.1.8) so a ruleset update never changes results without a commit on your side.
  • Each SARIF rule carries security-severity (9.5 / 8.0 / 5.5 / 3.0 / 1.0 for critical → info) and CWE / OWASP tags, and each result a sphiorFingerprint, so GitHub ranks alerts and tracks them across commits.
  • Accepted findings are not written to SARIF, because GitHub code scanning ignores SARIF suppressions and would show them as open alerts. Use --suppressed to keep that record.
  • Uploading SARIF to a private repository requires GitHub Advanced Security. Without it, keep the --fail-on step and drop the upload.

Any other CI works the same way: run the command, read the exit code, archive the SARIF or JSON.

On GitHub, the SPHIOR CODE Security Scan action does all of this in one step (uses: Toraastrta/sphior-scan-action@v1) and adds a job summary.

pre-commit

Scan before every commit with pre-commit. Add to .pre-commit-config.yaml:

repos:
  - repo: https://github.com/Toraastrta/sphior-code
    rev: main  # pin to a commit SHA for reproducible results
    hooks:
      - id: sphior-code
        # args: [--fail-on, critical]  # default: high

Then run pre-commit install. The hook scans the repository and lists each finding with its file, line and fix; a finding at or above the threshold stops the commit. It needs Node.js 18 or later, which pre-commit provides if it is not installed.


Excluding paths and accepting findings

Two different things, kept apart on purpose:

  • Exclude — do not read the file at all (generated code, vendored code). No findings are produced; the summary reports how many files were excluded.
  • Accept — the file is scanned and the finding is produced, then recorded as accepted with a reason (test vectors, fixtures, a deliberate fixed input). Accepted findings move out of the results and into --suppressed.

.sphiorignore

Put it at the root of the scanned directory. One entry per line: <glob> [rule_id] [# reason].

# exclude: no rule id
generated/**
third_party/

# accept one rule (or a family, with a trailing *) in a path, with a reason
test/fixtures/**   secret.*                 # fake keys used by the test suite
docs/examples.py   pattern.py.weak_hash     # shown as a bad example on purpose
  • ** matches across directories, * and ? within one. A glob without wildcards also matches everything below it.
  • Lines it cannot interpret are reported as warnings, never silently dropped.

Inline comments

Works with any line-comment syntax (//, #, --, ;). The marker must end the line, apart from an optional : reason.

eval(template); // sphior-ignore: input is a constant from build time

// sphior-ignore-next-line secret.private_key: header string used in documentation
const header = "-----BEGIN RSA PRIVATE KEY-----";

A rule id is optional (without one, every finding on that line is accepted). Accepting without a reason is allowed, but the CLI counts and reports those so they can be reviewed.


VS Code

Install SPHIOR CODE from the Visual Studio Marketplace or Open VSX (for Cursor, Windsurf, VSCodium). Requires VS Code 1.85 or later. Node.js does not need to be installed separately.

  • Findings appear in the editor and the Problems panel as you open and edit a file, with the source SPHIOR, the rule id as the code, and a link to the CWE.
  • Severity maps to the editor's levels: critical and high → Error, medium → Warning, low → Information.
  • Each finding offers a quick fix, SPHIOR: Fix "…" with your AI. It copies a ready-to-paste prompt (finding, location, why it matters, remediation steps) to the clipboard and writes it to the SPHIOR CODE output channel.
  • Because the diagnostic message already contains the remediation, the "Fix with AI" action in Copilot or Cursor works on it directly.
  • Setting: sphior.enable (default true). Reload the window after changing it.

The extension analyses the files you open. To scan the whole repository, use the command line or the MCP server. AI-AUTOFIX.md has rules you can give Cursor, Copilot or Claude Code so they fix SPHIOR findings without being asked.


JetBrains IDEs

Install SPHIOR CODE from the JetBrains Marketplace. It works in every JetBrains IDE from 2024.2, because files are matched by name rather than through a language plugin.

  • Requires Node.js. The plugin looks for node in SPHIOR_NODE_PATH, then on PATH, then in common install locations (Homebrew, /usr/local/bin, nvm, fnm, Volta, Program Files\nodejs). If none is found, it shows a notification with a download link.
  • Requires LSP4IJ. The Marketplace installs it automatically.
  • Findings appear in the editor with the same messages, severities and quick fix as in VS Code.

Zed

Two extensions, because Zed keeps language servers and MCP servers apart:

ExtensionWhat it does
sphior-code-lspFindings in the editor as you type, in JavaScript, TypeScript, Python, Go, Rust, C, C++, PHP, Ruby, Java, Kotlin, Scala, Swift and C#.
sphior-code-mcp-serverConnects Zed's agent to the MCP server.

Both use Zed's own Node.js and install the scanner from npm on first use (@sphior/scan and sphior-code-mcp), so there is nothing else to set up. Neither needs an account; the MCP server takes an optional API key in its settings.

They are submitted to Zed's extension registry. Until they appear there, install them from a clone: open Extensions, choose Install Dev Extension, and select packages/sphior-zed/lsp, then packages/sphior-zed/mcp-server.


AI coding assistants (MCP)

sphior-code-mcp is a Model Context Protocol server. It lets the assistant you already use — Claude Code, Cursor, GitHub Copilot, Windsurf, Cline, Continue, Zed, JetBrains AI Assistant — scan your workspace and fix what it finds. SPHIOR finds; your assistant writes the fix.

Set it up

# Claude Code
claude mcp add sphior-code -- npx -y sphior-code-mcp
// Cursor (~/.cursor/mcp.json), Windsurf, Cline, Claude Desktop and others
{
  "mcpServers": {
    "sphior-code": { "command": "npx", "args": ["-y", "sphior-code-mcp"] }
  }
}
// GitHub Copilot in VS Code (.vscode/mcp.json)
{
  "servers": {
    "sphior-code": { "type": "stdio", "command": "npx", "args": ["-y", "sphior-code-mcp"] }
  }
}

It is also listed in the MCP Registry as io.github.Toraastrta/sphior-code-mcp.

What the assistant can do with no account

ToolWhat it does
get_fix_contextScans the workspace (or path) and returns one entry per place to fix. Filter with severity or a findingId.
health_checkReports the mode, the version and which tools need an account.

Each entry in get_fix_context contains:

  • location — file and line. The code itself is not included; the assistant opens the file in your workspace.
  • why and remediation_steps — deterministic guidance, written per finding.
  • also — other findings on the same line, so one edit clears all of them.
  • masked_preview, cwe, owasp, references.
  • agent_instructions — tells the assistant not to dismiss the finding, never to print or commit a secret value, and that a human reviews the change before merge.

Environment variables

VariableDefaultPurpose
SPHIOR_WORKSPACEthe directory the client started inDirectory to scan
SPHIOR_TIMEOUT30000Scan or request timeout in ms (1000–300000)
SPHIOR_DEBUGoffVerbose logs to standard error
SPHIOR_API_KEY—Optional. Connects to your SPHIOR account (below).
SPHIOR_API_BASEhttps://sphior.com/api/v1Override the account API endpoint

With a SPHIOR account

Setting SPHIOR_API_KEY (create one under Settings → API at sphior.com/app) adds tools that read the repositories you connected on GitHub:

ToolWhat it does
list_findingsOpen or resolved findings, filtered by severity, up to 100 at a time
get_findingOne finding in full
get_security_summaryOpen findings by severity, last scan, repositories monitored
resolve_findingMark a finding as fixed, with a reason
mark_false_positiveMark a finding as a false positive, with a reason
verify_evidenceVerify the scan-record chain of a repository, optionally with a downloadable evidence pack

Keys start with sk_live_; any other value stops the server at start-up with the reason, rather than failing later. Without a key these tools return a message explaining what they need, rather than failing silently. The local scan never contacts SPHIOR's servers in either mode.


Agent skills

Four skills teach a coding agent how to work with SPHIOR CODE — not just how to run it, but what to do with the result. They use the open SKILL.md format, so the same files work in Claude Code, Codex, Cursor, GitHub Copilot and claude.ai. They live in plugin/skills/.

SkillStarts when you sayWhat the agent does
fix-security-findings"scan this project", "fix the security issues", "any hard-coded keys?"Scans, opens each location, applies the remediation (one edit for everything in also), scans again to confirm, runs your tests, and tells you which credentials must be rotated
triage-security-findings"these are false positives", "this is test data", "too many findings"Reads each finding in context and sorts it into real / test data / false positive / not our code. Fixes the real ones; records the others in the narrowest form, always with a rule id and a reason; re-scans to prove nothing else disappeared; gives you a table to review
setup-security-ci"add security scanning to CI", "block merges with secrets"Measures the current state, agrees a --fail-on threshold with you, pins the scanner version, and writes the GitHub Actions, GitLab CI or other CI step — with SARIF upload where your repository supports it
pre-release-security-check"is this ready to ship?", "check before release"Runs one scan against fixed criteria — no exposed secrets, no open critical or high — and reports Ready or Not ready with the evidence and the versions used

What every skill is told: never make a finding disappear without fixing it or recording a reason, never print or commit a secret, never present a clean scan as more than it is, and leave the final decision to a human before merge.

The skills get findings from the MCP server when it is installed, otherwise from the command line. Neither needs an account.

Claude Code

This repository is a Claude Code plugin marketplace. One install adds all four skills:

/plugin marketplace add Toraastrta/sphior-code
/plugin install sphior-code@sphior

The skills run the scanner through the command line (npx @sphior/scan). To give them the MCP server as well, add it once:

claude mcp add sphior-code -- npx -y sphior-code-mcp

Cursor

This repository is also a Cursor plugin. It adds the MCP server (pinned to sphior-code-mcp@1.1.12) and all four skills to Cursor's agent. To install it from a clone:

git clone --depth 1 https://github.com/Toraastrta/sphior-code.git ~/.sphior-code
mkdir -p ~/.cursor/plugins/local
ln -s ~/.sphior-code/plugin ~/.cursor/plugins/local/sphior-code

Then run Developer: Reload Window. The skills appear under the plugin, and Cursor asks you to approve the MCP server plugin-sphior-code-sphior-code the first time it starts. Neither needs an account. To update, run git -C ~/.sphior-code pull and reload.

If you only want the skills, copy them as described in the next section.

Codex, Cursor, GitHub Copilot

Copy the skill folders into the directory your agent reads:

AgentIn one repositoryFor all your projects
Codex.agents/skills/~/.agents/skills/
Cursor.agents/skills/ or .cursor/skills/~/.agents/skills/ or ~/.cursor/skills/
GitHub Copilot (VS Code agent mode, Copilot CLI).agents/skills/ or .github/skills/—

All three read .agents/skills/, so one copy in the repository covers them all:

git clone --depth 1 https://github.com/Toraastrta/sphior-code.git /tmp/sphior-code
mkdir -p .agents/skills
cp -R /tmp/sphior-code/plugin/skills/* .agents/skills/

Restart the agent if a skill does not appear. In Codex you can also call one explicitly, for example $pre-release-security-check. For the MCP server, see Set it up; without it, the skills run the command line through npx.

claude.ai and Claude Desktop

  1. Download the skill ZIPs from the latest release.
  2. In Settings → Capabilities, make sure code execution is on, then under Skills choose Upload skill and upload each ZIP.

claude.ai cannot see your local files, so attach the scan output instead: run npx @sphior/scan run . --fix-context sphior-fix.json (or --json) on your machine and add the file to the conversation. The skill works from it.


Evidence records

packages/sphior-scan/src/engine/evidence is the tamper-evident side of the engine, published in the open so that anyone can check a record without trusting whoever produced it:

../canonical.tsCanonical JSON (RFC 8785) so the same data always hashes the same
record.tsOne scan as one record: repository, branch, commit, engine and ruleset versions, time, finding counts, scan scope, the Merkle root of the findings, and the hash of the previous record
../scope.tsWhat a scan covered and what it did not: files considered and analysed, files left out by reason, languages, and the limits applied. Recorded inside the hashed record, so the gaps are as verifiable as the findings
merkle.tsMerkle root over finding fingerprints, in sorted order
chain.tsRecompute each record hash and check the link to the previous record
pack.tsEvidence pack: per-file SHA-256 and a manifest hash, and the check that verifies it
verify-rows.tsVerify a chain from stored rows and rebuild the pack

These are library functions exported from the engine. The CLI does not write records on its own; the hosted service writes one per scan, and verify_evidence checks them.


Privacy and data boundary

  • The scanner makes no network requests. No source upload, no telemetry, no analytics, no update check. It works with networking disabled.
  • Verify it yourself. git grep 'fetch(' in packages/sphior-scan/src does return hits. All of them are either detection rules that look for fetch / axios as an SSRF sink in your code, or builders for reference links that are printed, never requested. The same holds for the bundled server.cjs in the published extensions.
  • Secret values are never stored or transmitted. Findings carry a masked preview and a hash.
  • AI fix context contains no source code. Only the location, the rule, and the remediation.
  • The MCP server's local scan never contacts SPHIOR. With SPHIOR_API_KEY set, the account tools send finding identifiers and your reasons for resolving them — not source code.

What it does not do

Stated plainly, so a clean result is not read as more than it is:

  • Data flow stays within one file. Untrusted input that crosses files, or passes through closures and callbacks, is not followed. The engine stays silent rather than guessing.
  • It does not scan dependencies. The CLI reads source files, not lockfiles. Known-vulnerable dependencies are checked by SPHIOR CODE on GitHub.
  • It is not a penetration test, and it does not see your runtime: vulnerabilities in the language runtime or in a server you deploy are invisible to a source scanner.
  • It does not judge compliance. It records what it found; it does not decide whether you pass an audit.
  • The editors scan open files, and the editor integrations do not read .sphiorignore (inline comments do work there).

SPHIOR CODE on GitHub

Everything above is free, unlimited and local. The hosted service adds what a laptop cannot keep: continuous scanning of your repositories and a history that outlasts any single run.

Install the SPHIOR CODE GitHub App and it:

  • scans every pull request and every push to the default branch, with no configuration;
  • reports in a Check Run with line annotations, and fails it when there is a Critical or High finding;
  • checks dependencies in 8 ecosystems (npm, PyPI, Go, RubyGems, Packagist and others) against OSV advisory data, with the version to upgrade to;
  • keeps a monthly ledger of dependency versions, re-checks it daily against new advisories, and alerts you when a dependency you already ship becomes vulnerable;
  • marks findings resolved automatically when a later scan no longer sees them, and records the fixing commit;
  • writes a chained, verifiable record of every scan (the evidence records above), which verify_evidence and the API can check independently;
  • shows findings, dependencies and settings in the SPHIOR console, with links that open the fix in Claude Code, Cursor or Codex.

Source is read in memory during the scan and is not stored. On the hosted service, data-flow analysis currently covers JavaScript and TypeScript, and other languages are checked with the pattern rules; for the full multi-language data-flow analysis described above, also run the CLI in your CI.

The free plan includes dependency scanning. Code scanning is part of the paid plans — see sphior.com/code for current plans.


AI governance MCP server

packages/ai-governance-mcp (sphior-ai-governance-mcp, Apache-2.0) is a separate MCP server for recording what AI agents did — actor, model, provider, policy decision, tokens (optionally split into input, output and cache), cost, latency, trace id — as tamper-evident evidence for ISO/IEC 42001, the EU AI Act and SOC 2 reviews. Only hashes and metadata are kept, never prompts or outputs.

  • Tools: record_ai_execution (one event) and record_ai_executions (up to 200 events).
  • Requires SPHIOR_AIGOV_TOKEN, created under Settings at sphior.com/app. Without it the server still starts and explains how to get one.
  • It records facts. It does not decide whether you comply.

See its README for setup.


Versions

PackageVersionRuleset bundled
@sphior/scan (CLI, language server)0.1.92026.10.23-24
sphior-code-mcp1.1.122026.10.23-24 (through @sphior/scan 0.1.9)
Claude Code / Cursor plugin sphior-code0.3.0four skills; the Cursor plugin also starts sphior-code-mcp@1.1.12
VS Code extension, Visual Studio Marketplace0.1.52026.10.23-24
VS Code extension, Open VSX0.1.52026.10.23-24
JetBrains plugin0.1.12026.07.12-22
sphior-ai-governance-mcp0.2.4—

All surfaces run the same engine code, but each is released on its own schedule, so a surface can bundle an earlier ruleset than the CLI for a while. Every run prints its engine and ruleset versions, and every SARIF file records them, so a result can always be traced to the exact rules that produced it.


Repository layout and building from source

.claude-plugin/          Claude Code marketplace manifest
plugin/                  Claude Code plugin (MCP server pin + fix-security-findings skill)
packages/
├── sphior-scan/         Detection engine + language server + CLI   (@sphior/scan)
│   ├── src/engine/        rules, taint analysis, suppression, SARIF, evidence records
│   ├── src/*-ast.ts       tree-sitter backends, registered at start-up per language
│   ├── src/interproc.ts   cross-function data-flow shared by the tree-sitter backends
│   └── src/lsp/           Language Server Protocol implementation
├── sphior-vscode/       VS Code extension   (bundles the language server)
├── sphior-jetbrains/    JetBrains plugin    (LSP4IJ + the same language server)
├── code-mcp/            MCP server          (sphior-code-mcp)
└── ai-governance-mcp/   AI governance MCP   (sphior-ai-governance-mcp)

Requires Node.js 18+.

# 1. engine + language server + CLI
cd packages/sphior-scan && npm install && npm run build
node dist/cli.js run ../../your-project

# 2a. VS Code extension (bundles the server built in step 1)
cd ../sphior-vscode && npm install && npm run build

# 2b. JetBrains plugin (JDK 21)
cd ../sphior-jetbrains && ./gradlew buildPlugin

# 3. MCP server
cd ../code-mcp && npm install && npm run build

The Gradle build copies the language server from step 1 before packaging and fails rather than bundling a stale one.

Related

License

MIT — see LICENSE. packages/ai-governance-mcp is Apache-2.0.