{
  "version": "act 2.0.0",
  "slug": "security-surface",
  "name": "security-surface",
  "description": "Use to produce an application-security surface report for a file or module \u2014 dangerous constructs, secret-touching code, and source\u2192sink taint flows. Composes unsafe_surface + secret_surface + taint_flow + analyze_surface. Architecture tier (taint_flow is Architecture). Inline by default; artifact mode for human-initiated audits or High/Critical verdicts.",
  "url": "https://act101.ai/docs/skills/security-surface",
  "body_md": "# Security Surface\n\n**Composes (ops only \u2014 never other skills):**\n\n| Tool | Purpose | MCP call | Tier |\n|------|---------|----------|------|\n| `unsafe_surface` | Dangerous constructs (eval, raw SQL, FFI, unsafe blocks, reflection, deserialize) | `unsafe_surface` with `file: <F>` | Free |\n| `secret_surface` | Credential params, tokens, signing keys, env reads, hardcoded secrets | `secret_surface` with `file: <F>` | Engineer |\n| `taint_flow` | Source\u2192sink data-flow paths from an entry function | `taint_flow` with `target: <fn>, file: <F>` | Architecture |\n| `analyze_surface` | API surface area at the module boundary (context) | `analyze_surface` | Engineer |\n| `scan` | Repo-wide superset: credential (pattern + entropy) / AI-config-backdoor / MCP-RCE / typosquat-dependency / Actions-injection / LLM-output-to-exec / prompt-injection-surface detectors across the whole tree + Health Score | `scan` with `root: <repo>` | Free (public) / scan entitlement (private) |\n\n**Tier:** Architecture (the max of composed op tiers; `taint_flow` gates it).\n\n## When to use\nBefore merging or shipping code that handles untrusted input, on a security review,\nor when asked \"what's the attack surface of X?\". For a single entry point, pass its\nfunction name as `taint_flow`'s `target`.\n\nFor a **whole-repo** read (not a single file/module), call `scan` \u2014 it runs the\nfull detector set across the tree (credentials incl. the entropy heuristic,\n`.cursorrules`/AI-config backdoors, MCP-config RCE, typosquat/hallucinated\ndependencies, GitHub Actions expression injection, LLM-output-to-exec taint,\nprompt-injection surfaces) and returns the AI-Code Health Score. Use the\nper-file ops above for a focused single-file/module surface.\n\n## Procedure\n1. `unsafe_surface(file)` \u2014 collect dangerous constructs with confidence.\n2. `secret_surface(file)` \u2014 collect secret-touching symbols.\n3. For each entry function in the file (exported / request handler / `main`), run\n   `taint_flow(target, file)` \u2014 collect source\u2192sink flows + the frontier.\n4. `analyze_surface` \u2014 note how exposed the module is (context for severity).\n\nIf `taint_flow` is unavailable (below Architecture), run steps 1\u20132 + 4 and caveat the\nverdict: \"taint flows not analyzed (Architecture tier required).\"\n\n## Honesty caveat (read first)\n\n`taint_flow` coverage is reported per call in `modeled_kinds` \u2014 read it; never\nassume a fixed list of \"supported\" grammars. Per the COVERAGE LAW taint applies\nto **every applicable tier-1+ grammar**, so there is no language subset to\nenumerate:\n\n- A non-empty `modeled_kinds:{taint}` means taint **was modeled** for this\n  grammar; an empty `flows` result is then a genuine **\"no source\u2192sink flow\n  found.\"**\n- An **empty / absent** `taint` in `modeled_kinds` means taint was **not\n  modeled** for this grammar \u2014 **\"no evidence,\" not \"no taint.\"** Never emit a\n  Low / \"no taint flows\" verdict on that basis: name the language and caveat the\n  taint dimension as **not analyzed**, not clean. A not-modeled result is a\n  coverage gap to close, never a feature boundary.\n\n## Severity verdict\n\n| Verdict | Criteria |\n|---------|----------|\n| **Low** | No taint flows **AND taint was actually covered for this grammar** (real flows would populate); no high-confidence unsafe items; no hardcoded secrets. If taint is uncovered/not-modeled for the grammar, this is NOT Low \u2014 caveat the taint dimension as not analyzed (see Honesty caveat). |\n| **Medium** | Unsafe items present but no tainted flow reaches them; OR secret-touching code without hardcoded literals |\n| **High** | At least one source\u2192sink taint flow to a sink; OR a hardcoded secret literal |\n| **Critical** | A taint flow to a RawSql / CommandExec / Eval sink, OR a hardcoded signing key, on an exposed boundary |\n\nUse the highest applicable verdict. Caveat when a tool was skipped or when\n`modeled_kinds`/`frontier` show the analysis was partial (e.g. \"flow analysis\nincomplete \u2014 unresolved callees: \u2026\").\n\n## Summary format\n\n```\n## Security Surface: <file / module>\n\n**Severity: <Low / Medium / High / Critical>**\n- Taint flows: N (sinks: <RawSql x2, Eval x1, \u2026>) \u2014 or \"none / not analyzed (tier)\"\n- Unsafe constructs: N (<eval x1, raw_sql x2, \u2026>)\n- Secret touches: N (<hardcoded_literal x1, token_var x2, \u2026>)\n- Frontier (unresolved tainted callees): <list, or \"none\">\n\n**Top risks:** <ranked source\u2192sink flows and high-confidence unsafe/secret items>\n**Suggested:** <e.g. \"parameterize the SQL at <loc>\", \"move the hardcoded key to env\", \"resolve <callee> to complete flow analysis\">\n**Coverage caveat:** <modeled_kinds gaps / skipped tools / partial flow>\n```\n\n## Artifact mode\nInline by default (return the summary to the caller, no files). For human-initiated\naudits or a High/Critical verdict, follow the artifact protocol in\n`../analysis-protocol/references/protocol.md` (write `docs/act/<timestamp>/` with\n`manifest.json`, `raw/*.json`, `report.md`).\n\n## Project Map Updates\nNone. Reads `project-map.md` for context (entry points, risky files) but does not modify it."
}