Source audit (Code Scan)
The second engine: SiteCMD walks your linked project folder and audits the source for the issues a live-site scan can't see.
SiteCMD’s source audit, called Code Scan in the app, examines a linked project folder for security, database, AI-runtime, architecture, operations, dependency, and agent-configuration risks that a live response cannot show. It is static analysis: findings describe source and configuration evidence, not proven runtime behavior.
When it runs
Link a project folder when you create the project or later in project settings. A Full Scan runs Web Scan first and then Code Scan. You can also run Code Scan by itself. A Web-only scan does not audit the folder, and Code Scan cannot run without a linked folder.
Outside the desktop app, run the same local source audit from a checkout with
sitecmd audit .. Use --format github --fail-on high for a free CI gate, or
--format review --output sitecmd-review.md for a standalone review artifact.
Everything happens locally:
- The audit reads files from the linked folder
- The analysis runs on your machine
- Results are written to the local SiteCMD database
- Source and configuration evidence is not uploaded
Code Scan does not contact package registries. Its dependency findings come from local manifests, lockfiles, imports, workflow files, and package-manager configuration. Package-version and advisory lookups belong to the separate Updates workflow.
Ordinary Code Scan does not read values from non-example dotenv files or open a database. One explicit per-run option enables database analysis: Inspect local database schemas reads local dotenv values only to discover a target, then queries schema and migration metadata, never application table rows. SQLite files must be inside the linked project and are opened read-only. Every Postgres host and hostaddr must be loopback, or the connection must use a local Unix socket, and its catalog queries run in a read-only transaction. Remote and mixed-host targets are rejected. The option resets to off and scheduled scans never enable it. The CLI equivalent is sitecmd audit . --inspect-local-databases.
What the audit looks for
The pipeline has collection, four analysis passes, and finalization.
1. Collect files
SiteCMD walks the linked root and looks for at least one recognizable marker:
- A project manifest:
package.json,composer.json,Cargo.toml,go.mod,pyproject.toml,requirements.txt, orGemfile - A framework or schema config: a Next.js, Vite, Astro, or Drizzle config file, or
schema.prisma - A source layout:
src/,app/,pages/,components/,lib/,api/,functions/,prisma/,migrations/,supabase/,db/, or WordPress/Drupal content directories
If none of those exist, the audit stops and asks you to point at a different folder. This guards against accidentally running against a download folder, a desktop, or some other location that isn’t actually a project root.
The entry point is canonicalized and must remain under your home directory. The walker skips symlink entries, rechecks canonical paths before reading, refuses out-of-root targets, and opens files without following the final symlink on supported Unix systems.
Collection is deliberately bounded. The current limits are 5,000 analyzed source files, 100,000 inventoried project files, 64 MB of analyzed source, 1 MB per source file, and 48 directory levels. Generated, dependency, build, coverage, cache, and known vendored directories are skipped. Minified bundles, declaration files, recognized third-party library bundles, test files, and example files are inventoried where useful but excluded from ordinary per-file source findings.
Per-file analysis currently reads JavaScript, TypeScript, Python, PHP, Ruby, Go, and Rust source extensions. Other project files can still feed targeted config, manifest, workflow, schema, migration, and operations checks.
2. Analyze source
Per-file analysis looks for bounded patterns such as:
- Request-to-sink risks. Same-file evidence around command execution, dynamic evaluation, SQL construction, template evaluation, path use, file inclusion, unsafe deserialization, redirects, server-side fetches, and raw HTML rendering. The finding explains when full value-flow or reachability review is still required.
- Route protections. Recognized validation, authentication, authorization, tenant scoping, CSRF, rate-limit, upload, webhook, OAuth, token, and session-cookie controls. Route and middleware awareness exists for selected frameworks, but unsupported wrappers and centralized controls can require manual review.
- Service boundaries. CORS policy, disabled TLS verification, external-call timeouts/retries, Stripe checkout inputs, transaction boundaries, and database access mixed into route handlers.
- AI runtime safety. Timeouts, concurrency, request/output limits, model or setting control, retry/loop bounds, spend guardrails, observability, caching, and kill-switch clues around recognized AI providers.
- Architecture and hygiene. Oversized modules/routes, empty catch blocks, console-only error handling, repeated database access, N+1-like loops, broad TypeScript
any, placeholder density, and generated-conversation residue. - Secret-shaped literals. Credential-shaped values, client-visible secret env use, weak default credentials, plaintext password handling, and committed-config patterns. Values are redacted from evidence; static matching does not establish that a credential is live, privileged, tracked, or deployed.
These are source patterns with framework-aware exclusions, not a compiler, symbolic executor, or complete interprocedural data-flow engine.
3. Supply chain
Code Scan’s dependency pass currently focuses on the local JavaScript/npm project graph: package.json, package-lock.json, classic yarn.lock, pnpm-lock.yaml, .npmrc, JavaScript/TypeScript imports, package scripts, Dockerfiles, and GitHub Actions workflows.
It can surface:
- Imported packages not matched to a scanned declaration, workspace package, recognized framework namespace, or parsed TypeScript path alias
- Declared dependencies with no recognized source, script, config, or framework usage evidence
- Missing or mismatched lockfile entries, unexpected registry hosts, direct URL dependencies, weak lockfile integrity metadata, and unbounded ranges
- Package names that resemble a curated popular package name, reported as review evidence rather than proof of a malicious package
- Literal npm auth values, unpinned Docker bases, remote pipe-to-shell commands, and missing package release-age policy
- GitHub Actions pinning, permission, expression-injection, and
pull_request_targetcheckout risks
This pass does not query advisories, prove a package is malicious, or report whether a version is current. Use Updates for supported ecosystem registry/version checks and a dedicated software-composition analysis tool for authoritative vulnerability coverage.
4. Operations
Project-level checks cover:
- Release and recovery clues. Health-check routes, error reporting, structured logging, rollback/recovery/backup documentation, migration workflow, job visibility, and error-boundary markers. A missing recognized marker does not prove an external platform or organization process is absent.
- Project hygiene. Env examples and drift, gitignore rules, automated-test markers, critical-path test clues, lint/build scripts, CI and quality gates, optional pre-commit hooks, TypeScript strictness, and supported runtime versions.
- Framework debug posture. Recognized production-risk settings such as Django, WordPress, or Laravel debug configuration, with severity based on the exact matched condition.
- Database source posture. Prisma and Drizzle schema/migration structure, Supabase row-level-security policies, relation/index/uniqueness clues, and server/client role separation.
- Local database comparison. When the user explicitly enables inspection for that run and a bounded local SQLite or loopback Postgres target is available, schema and migration metadata can be compared with checked-in Prisma/Drizzle/Supabase artifacts. Unreachable or unsupported targets do not become fabricated drift findings.
5. Review AI setup
The AI Setup pass inspects recognized agent instruction and MCP configuration files for stub content, fragmented/conflicting instruction surfaces, legacy formats, and secret-shaped literals. It evaluates file structure and bounded text patterns, not the quality of every instruction or the behavior of an external agent.
6. Finalize
After all four analysis phases, the results are normalized:
- Every known detector is registered with an authoritative domain, severity policy, scan phase, and Critical-eligibility rule
- Findings are sorted by severity, then by file path, then by title
- Duplicate IDs are removed after all passes
- Selected framework-wide auth evidence can suppress route findings that the same-file check could not see
- Canonical check IDs let equivalent Web Scan and Code Scan evidence group into one issue without discarding their separate instances
The final list lands in the Issues view, merged with the live-site findings into one ranked list.
Risk categories
Source-audit findings get classified into risk categories that overlap with live-site findings but include some source-specific ones:
| Category | What it covers |
|---|---|
| Database Analysis | Query safety, schema and migration clues, Supabase policies, and bounded local database comparison |
| AI Safety | Timeouts, retries, quotas, spend controls, loops, concurrency, and rollout safety around recognized AI providers |
| Security | Auth, authorization, request handling, injection sinks, secrets, transport policy, and other code-level risks |
| Architecture | Oversized modules/routes, data-layer coupling, error handling, type-safety, test coverage, and maintainability |
| Operations | Env drift, debug settings, CI/build gates, deploy safety, recovery, observability, and background-job visibility |
| Dependencies | npm graph consistency, package-name heuristics, registry/lockfile integrity, build inputs, and workflow hardening |
| AI Setup | Recognized agent instruction files, editor rules, and MCP configuration structure |
These are the same domain labels the app uses for Code Scan summaries and filters. The headline SiteCMD Score is computed once across deduplicated active issue groups; Code Scan is one evidence source, not a second competing score.
What every issue contains
An expanded Code Scan issue includes a title, bounded description, severity, confidence, file path and optional line, a redacted source excerpt/evidence summary, why the condition matters now, a likely fix, and a verification hint. The fields are detector-specific and should agree with one another:
- Severity reflects the plausible impact of the observed condition, with Critical restricted to a small reviewed set of direct high-impact sink patterns.
- Confidence says whether the evidence is direct, high-confidence, or still needs review. A review-level issue cannot trigger the score’s exploitable cap.
- Evidence describes the matched condition without printing secret values, credential-bearing URLs, or other sensitive source content.
- Likely fix is conditional on the evidence. It should not tell you to install, delete, rotate, or rewrite something the scan did not establish.
- Verification names a safe check that can show the condition cleared; it does not recommend proving an exploit against a real system.
Finding detail
The complete Code Scan payload is part of the free local workbench. Every issue includes its full detail, bounded evidence, fix guidance, and verification context. Rust returns the same local payload regardless of subscription state; there is no redaction layer or frontend feature gate.
For a site you explicitly connect, the service receives the bounded finding identity documented in Privacy & data, not source excerpts, file paths, line numbers, or repository contents.
Big projects
Runtime depends on file count, file size, storage speed, available CPU, and whether a permitted local database responds before its connection deadline. Per-file analysis uses available CPU cores, but large projects still take longer.
If you only care about one application in a monorepo, link that application directory when it contains a recognized root marker. This also reduces the chance that another package consumes a scan budget before the relevant files are reached.
What the audit does not do
- It does not run application code. SiteCMD does not spawn your build, execute project scripts, or run your tests. The optional local database phase performs read-oriented schema/catalog inspection only.
- It does not modify your files. The audit is read-only. No code is rewritten and no files are created in your project.
- It does not query dependency advisories. Code Scan does not claim CVE coverage or current-version status from local lockfiles alone.
- It does not prove exploitability. Static matches can miss framework indirection and can require value-flow, reachability, runtime configuration, or deployment review. Confidence and wording preserve that distinction.
- It does not replace a security audit. Some checks overlap with what a security review would catch, but the audit is not a substitute for actual review of an application that handles sensitive data.
- It does not inspect git history or tracked status. SiteCMD walks the filesystem. Findings about a local config file cannot establish that it was committed, shared, or deployed unless that evidence appears elsewhere.