references/desktop-scan.md
# Codex Desktop Standard Scan
Read this reference only after the host explicitly identifies itself as the Codex desktop app. Listed tools alone do not establish a desktop host.
## Resolve The Authoritative Scan
Resolve the target, requested scope, and user-provided security context before starting the scan.
- If the request already includes a `scanId`, call `get_codex_security_scan_context`, passing `handoffClaimToken` when provided, and continue that existing scan.
- Otherwise call `start_codex_security_prompt_only_scan` once with `mode: "standard"`, `targetPath`, `scope`, and any exact `userContext`. Require its authoritative `scan.scanId` and `scan.scanDir`; preserve its handoff token when provided.
- If the direct start fails or returns malformed context, surface that error. Do not invent scan ownership, start a replacement scan, open setup, or switch to a terminal workflow.
Use the returned `scanId`, `scanDir`, scope, and exact `userContext` throughout the parent workflow. Read `../../../references/desktop-config-preflight.md` and run capability preflight only after this authoritative context exists.
Use the existing desktop phase labels for work that actually occurs: threat mapping, investigation, parent-led validation, attack-path assessment, and report assembly. Preserve the authoritative scan ID and handoff token. Increase the investigator total before dispatching each newly discovered assignment; the concurrently running baseline is independent and does not inflate that total. Capture each completed, source-backed investigation as a real coverage surface before advancing its `review_receipts` progress count. Do not create separate receipt files. Advance later phase counts only after the corresponding finding or report artifact exists, and never invent counts, phase workers, or coverage.
## Complete The Same Scan
Save `complete: false` checkpoints as results arrive and validation decisions are made. Preserve pending candidates with their original evidence in `coverage.deferred`; they are not validated findings. When the audit finishes, record the final semantic scan draft once with `record_codex_security_scan_draft({ scanId, complete: true, handoffClaimToken?, scope?, threatModel?, findings, coverage })`. Supply the actual findings, source-backed coverage, and preserved threat model; let the workbench write the unsealed canonical artifacts and derive authoritative target, scope, coverage metadata, finding identities, and fingerprints.
Honor desktop handoff requirements for any per-finding write-ups before completion. After the semantic draft succeeds and all three canonical JSON files exist, call `complete_codex_security_scan` exactly once with the same authoritative scan ID and handoff token. Return only after completion succeeds and `report.md` exists, linking the generated report and canonical artifacts; retrieve the complete findings only when the user explicitly requests them. Include measured token usage when available and explicitly label partial or unavailable measurement.
For each reported finding, emit one `::code-comment{title="[<priority-label>] <title>" body="<explanation>" file="<absolute path>" start=<line> end=<line> priority=<priority-number> confidence=<0-to-1>}` review directive at its tightest `root_control` location, or the most relevant affected source location when no root control is identifiable. Map `critical`, `high`, `medium`, and `low` to `P0/0`, `P1/1`, `P2/2`, and `P3/3` respectively; keep its title and explanation consistent with the generated report.
If finalization fails, surface the exact error and preserve the durable scan for later continuation; do not retry completion in the same response, generate a replacement report, or claim success.
references/scan-artifacts-and-ledger.md
# Scan Artifacts And Ledger
Use this reference only for diff scans that need auditable candidate coverage or a changed-file review worklist. Standard and Deep scans do not use this reference.
## Artifact Requirements
- Load the per-scan threat model path from `../../../references/scan-artifacts.md` as the repo-specific threat-model source of truth.
- Use the artifact paths from `../../../references/scan-artifacts.md` for `seed_research.md`, `deep_review_input.jsonl` when a scoped file-review worklist is needed, `work_ledger.jsonl` when a scoped file-review worklist is needed, `raw_candidates.jsonl` when multiple file-review results are aggregated, `dedupe_report.md` and `deduped_candidates.jsonl` when cross-file dedupe is needed, and per-finding `05_findings/<candidate_id>/candidate_ledger.jsonl`.
## Seed Research
- First capture user-provided scope hints such as CVE/GHSA/advisory identifiers, package versions, named vulnerability families, or release/security-test references.
- When the user request or scan context includes CVE, GHSA, advisory, issue, release, package-version, or explicit vulnerability-family identifiers, run an advisory seed pass before deep frontier scanning and save it to the advisory seed research path from `../../../references/scan-artifacts.md`.
- Use relevant security guidance, user-supplied advisory text, and checked-out security tests within the authorized source state. Access external sources only when the user explicitly authorizes it; do not inspect unrelated Git history or later fixes. Record the sources searched, candidate files/functions/classes/hunks, expected vulnerable behavior, and any failed lookup attempts.
- Treat those candidates as seed rows only: validate the vulnerable behavior against the checked-out repository before reporting. Do not let the seed lane replace the scan's primary scope.
- When advisory context has a generic or unhelpful category, first inspect supplied advisory text and in-scope security tests. If that evidence is inconclusive, run a local regression-seed pass over project-specific protocol, parser, validator, and utility names plus the advisory terms; do not assume obvious hotspots are the intended security regression.
- When the seed pass or local search opens a candidate file, class, package, or hunk, create an exact seed-target row for that area before opportunistic same-family scanning. Run a short seed-first triage over that file/package and its immediate shared helper or caller chain, then close the row as `reportable`, `suppressed`, `not_applicable`, or `deferred`. A more obvious neighboring issue can be reported too, but it does not replace the seed-target row.
- Keep every user/advisory/tag-seeded boundary package or class family open until that exact area is closed as `reportable`, `suppressed`, `not_applicable`, or `deferred`. A broader same-family finding in a neighboring parser, auth flow, deserializer, or template engine does not implicitly close the seeded row.
- In advisory-led scans, treat the advisory, fix hunk, release note, or security test as evidence for the intended root cause, not as an exclusivity filter and not as a bare finding. Keep the exact seed row open until checked-out repository evidence independently supports or disproves the same source, broken control, and impact tuple.
## Subagent Requirements
- When a scan uses subagent-dispatch phases and subagents are available in the current tool set, use subagents for those phases.
- Explicit invocation of the top-level diff scan authorizes the subagent-dispatch phases described by that workflow.
- For JSONL worklist phases, spawn no more workers than the runtime's usable slots, wait for their concrete worker ids, validate each result, and then refill available slots. If a spawn is rejected, have the parent complete the unstarted work without narrowing coverage. On native v2, spawn self-contained workers with `fork_turns=none`; use `interrupt_agent` only to stop a still-running worker before a retry.
- Immediately after each delegated file-review, validation, or attack-path dispatch, emit `CODEX_SECURITY_WORKER_STATUS {"phase":"file_review","planned":6,"started":3}` with the actual phase and worker counts, including when no worker starts. Do not include worker ids, paths, prompts, errors, or other fields.
- File-review-subagent ownership: one file-review subagent owns one `deep_review_input.jsonl` row or one very small tightly coupled shard, max 5 files, and returns full-file receipts plus pre-dedupe finding objects for that assignment.
- File-review subagents are read-only with respect to the target code under review, but they are allowed and expected to write scan artifacts under the resolved numbered artifact directories, including `<discovery_dir>/work_ledger.jsonl`, raw candidate snippets in `<discovery_dir>/raw_candidates.jsonl`, and per-candidate ledger receipts under `<findings_dir>/<candidate_id>/` when those artifact paths are provided in the prompt.
- Validation-subagent ownership: one validation subagent owns one candidate finding, one deduped candidate, or one repository coverage-ledger row that needs validation closure. It writes or returns validation artifacts, the visible validation report update, and the validation candidate-ledger receipt for that assignment.
- Attack-path-subagent ownership: one attack-path subagent owns one validated candidate finding or one reportable/deferred validation closure row. It writes or returns attack-path facts, severity/policy analysis, the visible attack-path report update, and the attack-path candidate-ledger receipt for that assignment.
- Parent-agent ownership: the parent agent owns `deep_review_input.jsonl` generation, bounded subagent dispatch, work-ledger and candidate-ledger reconciliation, aggregation of subagent outputs, cross-file dedupe when needed, and final scan closure.
- Subagent prompts must carry the exact current scan instructions they are expected to follow. Do not rely on the subagent implicitly inheriting this skill, another phase skill, previous parent context, or a summarized reference name.
### File-Review Subagent Handoff
The parent agent should give each file-review subagent enough concrete context to execute its assigned row without relying on implicit parent context. Keep the prompt concise, but include:
- the assigned `deep_review_input.jsonl` row or tiny shard
- the scan target, scan mode, `repo_name`, `scan_id`, `artifacts_dir`, the relevant numbered artifact directories, and per-scan threat model path or summary
- the writable artifact paths for `<discovery_dir>/work_ledger.jsonl`, `<discovery_dir>/raw_candidates.jsonl`, and per-candidate ledger receipts under `<findings_dir>/<candidate_id>/`
- any user-provided comparison or seed artifact that should affect coverage, such as an HTML/markdown report, prior security-review output, advisory text, CVE/GHSA, release note, issue, or separate audit directory
- the expectation to read assigned files in full, read only the supporting files needed for concrete findings, and return or write full-file receipts, raw candidates, suppressions/deferred rows, and ledger receipts
The parent agent must reject or re-prompt any file-review subagent result that lacks full-file receipts, omits source/control/sink/impact for candidates, omits candidate-local validation or attack-path facts for reported candidates, or returns only "no bugs found" without closing the assigned row with evidence.
### Validation And Attack-Path Subagent Handoff
After discovery and dedupe, divide validation and attack-path work across subagents when multiple candidates or coverage-ledger rows need closure and subagents are available under the resolved scan authorization.
For validation subagents, include the candidate or ledger row, discovery evidence, relevant raw/deduped candidate ids, affected files, threat-model context, validation artifact/report paths, and the candidate-ledger path that needs the validation receipt. The validation subagent should preserve or suppress the assigned instance only; it does not own final report assembly or unrelated candidates.
For attack-path subagents, include the validated candidate or validation closure row, validation report path or summary, affected root-control and sink lines, threat-model context, attack-path report path, and the candidate-ledger path that needs the attack-path receipt. The attack-path subagent should produce reachability, counterevidence, severity/policy analysis, and final reportability facts for the assigned instance only.
The parent agent must reconcile validation and attack-path subagent outputs before final reporting. Do not finalize while any reportable, suppressed, not_applicable, or deferred candidate/ledger row lacks the required receipt or explicit proof-gap reason.
## Scoped Deep Review
- Use `deep_review_input.jsonl` as the canonical changed-file review worklist for diff scans.
- For diff-scoped scans, generate `rank_input.jsonl` deterministically from changed source-like files with `<python_command> <plugin_dir>/scripts/generate_rank_input.py make-diff-rank-input --repo <repo_root> --base <base> --mode revisions --head <head> --out <discovery_dir>/rank_input.jsonl` for PR, commit, and branch diffs, or `<python_command> <plugin_dir>/scripts/generate_rank_input.py make-diff-rank-input --repo <repo_root> --base <base> --mode local-patch --out <discovery_dir>/rank_input.jsonl` for a local patch, then copy every row into `deep_review_input.jsonl` with `<python_command> <plugin_dir>/scripts/generate_rank_input.py copy-deep-review-input --rank-input <discovery_dir>/rank_input.jsonl --out <discovery_dir>/deep_review_input.jsonl`.
- Diff-scoped scans do not rank or drop changed files before deep review. Every row in diff `rank_input.jsonl` must be copied into `deep_review_input.jsonl` and receive a full-file review receipt.
- Add directly supporting files required to understand the changed security behavior only when repository evidence shows they are needed; record the add-back reason in the work ledger or per-file result.
- Deep-review every file selected into `deep_review_input.jsonl`.
- Use `<discovery_dir>/work_ledger.jsonl` as the append-only record of claims and completions, and reconcile it against `deep_review_input.jsonl` so rows are not skipped or double-counted.
- Use subagents when available under the resolved scan authorization.
- A file-review subagent must read every assigned file in full, update the ledger receipt for those files, and return the raw finding results for that assignment.
- When a file-review subagent finds a plausible finding in its assigned file or shard, that same subagent should carry that finding through candidate-local validation and candidate-local attack-path analysis before handing it back. The raw result should include the source or privileged boundary, closest relevant control, sink or broken control, impact, validation method/evidence or exact proof gap, attack-path facts, and disposition.
- A file-review subagent may read the minimum supporting files needed to validate or explain a finding it discovered, but it does not own unrelated rows or final scan closure.
- If subagents are not available, iterate through `deep_review_input.jsonl` yourself with the same full-file standard.
- A file is not covered because it appeared in searches. It is covered only when the responsible subagent or parent agent returns a receipt showing the file was read in full.
- Record file-level completion, disposition, and a concise evidence note in `<discovery_dir>/work_ledger.jsonl`; do not create a separate per-file findings directory.
- Append normalized, pre-dedupe candidate objects to `<discovery_dir>/raw_candidates.jsonl` when multiple file-review results are being aggregated or cross-file dedupe is needed.
- Do not stop until every `deep_review_input.jsonl` row has a completion receipt.
## Candidate Finding Coverage
- Track candidate-finding coverage separately from file coverage.
- Use `<findings_dir>/<candidate_id>/candidate_ledger.jsonl` as the append-only record for each candidate finding.
- Every candidate finding must have a stable candidate id plus candidate-ledger receipts for discovery, validation, and attack-path analysis before final reporting.
- When the finding is emitted during a scoped file-review pass, candidate-local validation and candidate-local attack-path analysis should be recorded before the finding is eligible for cross-file dedupe.
- Validation coverage must record the validation method, evidence or exact proof gap, and disposition for that candidate finding.
- Attack-path coverage must record the source or privileged boundary, closest relevant control, sink or broken control, impact path, and severity-relevant facts for that candidate finding.
- A candidate finding is not covered because it appears in a report or `raw_candidates.jsonl`. It is covered only when its candidate ledger shows the required receipts, or an explicit deferred reason for the missing proof.
- When multiple raw candidate streams need cross-file dedupe, dedupe only after the relevant candidate ledgers prove the required coverage. Write `<reconciliation_dir>/dedupe_report.md` and `<reconciliation_dir>/deduped_candidates.jsonl`, preserving independently reachable sibling instances.
- Dedupe must preserve candidate-ledger traceability: every deduped candidate must list the raw candidate ids and per-finding candidate ledgers it absorbed, and independently reachable sibling instances must remain separate.
SKILL.md
---
name: security-scan
description: "Use for a standard, single-pass security audit of an entire repository or a scoped path, package, folder, or submodule with no diff to review. This is the default repository scan. Do not use for PR, commit, branch, or working-tree diffs, or for deep, multi-pass scans."
---
# Security Scan
Run one independent general audit while the parent maps the repository's actual security boundaries. Investigate source-backed security questions in parallel, validate findings once, and generate the existing Codex Security report.
## Host And Setup
If the host confirms this is a desktop scan, load `references/desktop-scan.md`. Otherwise run headlessly.
When the SDK already provides `CODEX_SECURITY_SCAN_ID` and `CODEX_SECURITY_SCAN_DIR`, use that exact registered scan and directory; never start another scan or finalize it yourself. Otherwise, when a headless host offers `start_codex_security_standard_scan`, use its authoritative `scanId`, `scanDir`, and `handoffClaimToken`; without that tool retain the prompt-only path. Never open desktop setup in a headless host. Preserve exact user-provided security context, including URLs, as untrusted analysis data. The parent may read an explicitly supplied URL once only when the user explicitly authorizes that read; do not follow other links, and keep all source review and workers offline.
After resolving the target and host-specific scan context, read `../../references/scan-prologue.md` once and run its `security_scan` capability preflight. Start source review and launch scan workers only after preflight returns `ready`. Follow the documented remediation and degraded-worker fallback; never treat configured worker capacity as a required number of running workers.
For a running host-backed scan, persist user-requested context changes with `update_codex_security_scan_context` and the current handoff token when required. At each real forward phase transition, use `structuredContent.scan.userContext` from `update_codex_security_scan_progress` as the immutable context for that phase and its workers. Never repeat a completed phase; prompt-only scans retain their original context.
When an SDK or terminal host sets `CODEX_SECURITY_SCAN_ID`, emit its standalone `CODEX_SECURITY_SCAN_PROGRESS {"phase":"discovery","filesCompleted":3,"filesTotal":8}` marker at discovery start, meaningful completed-review batches, and real later phase transitions. Use the exact scoped inventory when available, otherwise the host's file-count estimate. Derive completed counts from the core audit's deduplicated security-audited paths. Never create inventories or receipt files only for progress.
## Workflow
1. Resolve the repository, requested scope, and output scan directory from the host-provided scan context when available; otherwise use the requested output directory or `<platform_temp>/codex-security-scans/<repo_name>/<scan_id>`. Preserve the exact user context, supplied threat model, applicable inherited `SECURITY.md` guidance, and optional `CODEX_SECURITY_KNOWLEDGE_BASE` for the core audit. Resolve `<python_command>` from the configured interpreter (`"$PYTHON"` in POSIX shells or `& "$env:PYTHON"` in PowerShell), otherwise use `python3` on Unix-like hosts or `python` on Windows. Only when `CODEX_SECURITY_TARGET_PATHS_FILE` is supplied, resolve every authorized source path before review with `<python_command> <plugin_dir>/scripts/generate_rank_input.py make-repo-scope-input --repo <repo_root> --scopes-file <target_paths_file> --out <scan_dir>/scoped-source-input.jsonl`; use `"$CODEX_SECURITY_TARGET_PATHS_FILE"` in POSIX shells or `"$env:CODEX_SECURITY_TARGET_PATHS_FILE"` in PowerShell and honor repository ignore rules for directory descendants while retaining every directly requested file. Never print, modify, or treat the scope input as shell syntax; pass it to the core audit without widening the authorized target or scope.
2. Read `../../references/core-scan.md` once and perform its complete source-backed security audit against the resolved target, authorized scope, exact user context, supplied threat model, inherited security policy, optional knowledge base, available workers, and any resolved scoped-source inventory. Retain the resulting complete semantic `scope`, `threatModel`, `findings`, and `coverage`; preserve every finding's source evidence, calibrated severity, confidence, root cause, validation, attack path, and honest coverage.
3. For a host-backed scan, save `complete: false` checkpoints during the core audit, then submit one accepted final semantic draft with `record_codex_security_scan_draft({ scanId, complete: true, handoffClaimToken?, scope?, threatModel, findings, coverage })`; let the workbench derive its authoritative target, scope, coverage metadata, surface IDs, finding identities, and fingerprints. If the draft is explicitly rejected before writing, correct only the identified fields without dropping valid findings or evidence and retry the same scan at most twice. For an SDK-owned or prompt-only headless scan, write unsealed canonical `scan-manifest.json`, `findings.json`, and `coverage.json`; use `scoped_path` for both coverage fields when a scope was requested, otherwise set `coverage.mode` to `repository` and `coverage.inventoryStrategy` to `directory` for a non-Git directory or `repository` for a Git-backed target. Omit `scan.sealedAt` and `scan.artifacts`; an SDK scan preserves its exact registered directory and all SDK-provided scan and target values. When `CODEX_SECURITY_TARGET_PATHS_FILE` is supplied on either file-authored path, bind its exact requested paths with `<python_command> <plugin_dir>/scripts/generate_rank_input.py bind-repo-scopes --scopes-file <target_paths_file> --manifest <scan_dir>/scan-manifest.json --coverage <scan_dir>/coverage.json`, using the same shell-specific target-paths reference.
4. Verify all three canonical JSON files exist. For an SDK-owned scan, return control without finalizing, sealing, generating `report.md`, or starting another scan; the SDK owns completion. For another host-backed scan, call `complete_codex_security_scan({ scanId, handoffClaimToken? })` once. For a prompt-only headless scan, run `<python_command> <plugin_dir>/scripts/finalize_scan_contract.py --scan-dir <scan_dir> --source-root <repo_root>`. Outside the SDK path, return only after completion succeeds and the generated `report.md` exists; never write the report by hand or reread the complete canonical findings unless the user explicitly requests them. Report measured token counts when returned and label partial measurement or unavailable usage honestly.
Keep discovery, validation, and attack-path reasoning within this Standard workflow; do not invoke separate phase skills or load Deep or diff references. Never call Deep-only tools. Do not create ranking phases, per-file or per-candidate ledgers, separate phase worker pools, repeated phase reports, or receipt files.