SuperAPI AI Directory

orca-sec-scans

General & other

View repository

Updated 10-15 22:11

About this skill

Skill: orca-sec-scans

WHAT

Purpose and context

  • Purpose: A static security scanning workflow, read-only (Trivy does not modify code when scanning), usable both locally and in CI/Jenkins. Covers: dependency CVE (Go/Node/Python lockfile), misconfig (Dockerfile/compose/nginx), and secrets exposed in files. Beyond that static layer there are two more layers: DYNAMIC scanning to verify dev's default assumptions with real requests, and OUTWARD scanning (supply chain/branding, keyless).
  • Trigger (when to use):
    • User says "security scan", "scan", "trivy", "check CVE", "security scan", "are there vulnerabilities"
    • Before release / merging the deploy branch
    • Periodically in CI (trivy fs . --config trivy.yaml --exit-code 1)
    • Diff falls into the Trigger-conditions table (auth, user input, secret, new endpoint, payment/sensitive data, exposing app to public domain) → MANDATORY scan; user says "are there vulnerabilities", "is it safe yet" → always a trigger.
  • Non-goals: no mass auto-bump when the submodule has uncommitted changes; do not remove findings from the report (if accepted, write .trivyignore); do not commit reports to the deploy server; do not investigate threats beyond the broad scope in the cti-expert style (only a keyless supply-watch snippet).

Mental model

Trivy có chưa? → scope (lockfile) → quét static HIGH/CRITICAL → report JSON+HTML → tóm tắt + đề xuất fix → re-scan NONE, in parallel giả định dev → request thật (curl/dig/git diff) → xác nhận hoặc lỗ hổng, plus optional tên thương hiệu → biến thể tất định → DNS sống + CT log. A clean static scan does NOT mean it is safe.

Input and output contract

Field Required? Meaning
In source code directory (be, fe or .) has scan target; trivy.yaml if the repo has
In HOST / domain currently running for dynamic scanning to curl/dig and verify for real
In brand name no for supply-watch.py
Out security/trivy-report.json + security/trivy-report.html yes full report, just a review artifact
Out HIGH/CRITICAL table by target + suggested fix yes bump deps, non-root USER, rotate secrets
Out dynamic scan results yes each assumption: true/false with the command + actual HTTP/DNS code
Out re-scan results when there is a fix remaining = NONE
Out supply-watch report optional rc 0 clean, 2 has findings; crt.sh error → SKIP

Rules and capabilities

  • RULE-01 (MUST): Static (Trivy) + Dynamic (checklist above) are TWO different layers — run BOTH. Trivy catches CVE/misconfig/secret-in-file; it does NOT catch auth bypass, public exposure, CORS/CSRF logic, branch drift. Do not treat a clean Trivy report = safe.
  • RULE-02 (MUST): Do not trust the dev's default assumptions — every "login is already in place", "it's internal so it's safe", "it runs already" must be verified with a real request before concluding.
  • RULE-03 (MUST): Trivy does not modify code when scanning — safe to run at any time.
  • RULE-04 (MUST): Finding reviewed & accepted → record it in .trivyignore (1 ID/line + reason comment + date), do NOT remove it from the report.
  • RULE-05 (MUST): Do not commit security/*.json|html to the deploy server — it is only a review artifact.
  • RULE-06 (MUST): When deploying bonbon-ai: push only be and fe (2 submodules) to the server; tooling (trivy.yaml, security/, skill) does not go to the server.
  • RULE-07 (MUST): Every fix change must go through build/verify before commit (go build ./..., pnpm i, …).
  • Capabilities: install local scanning tools if missing; static scan read-only of source code; send real HTTP/DNS requests to the project's own host; modify manifest/Dockerfile when a fix is applied; read public CT log/DNS (keyless).

Failure boundaries

  • Cannot install Trivy → blocked, report to user.
  • Submodule has uncommitted changes → only propose fixes, no auto-bump.
  • Fix does not build (go build ./..., pnpm i) → failed, no commit.
  • No HOST to scan dynamically → partial: static only, clearly state the dynamic layer has NOT run, do not conclude "safe".
  • Secret flagged → rotate the key immediately (not just remove it from the file).
  • supply-watch cannot call crt.sh → SKIP, do not judge it clean.

HOW

Main workflow

Step Type Inputs Action Outputs/exit Failure/next
W01 effect machine Step 0 — Check + Install Trivy (MANDATORY to run first) trivy --version printed out install error → blocked
W02 deterministic repo Step 1 — Detect language via lockfile, skip build/vendor directories scope —
W03 deterministic scope Step 2 — Scan vuln + misconfig + secret, HIGH/CRITICAL first findings —
W04 deterministic findings Step 3 — Export JSON + HTML report to security/ 2 report files —
W05 judgment findings Step 4 — Summarize HIGH/CRITICAL by target + propose fixes table + proposals dirty submodule → propose only
W06 deterministic target fixed Step 5 — Re-scan to confirm remaining = NONE still there → go back to W05
W07 effect HOST, diff DYNAMIC scan: run the checklist of 8 dev assumptions with real requests each assumption has evidence no HOST → partial
W08 deterministic brand name Scan OUTWARD with supply-watch.py (B03) rc 0 or 2 crt.sh error → SKIP

Details of each step (source of truth for W01–W08):

Workflow

Step 0 — Check + Install Trivy (MANDATORY run first)
if ! command -v trivy >/dev/null 2>&1; then
  echo "Trivy chưa có → cài…"
  if [[ "$(uname)" == "Darwin" ]]; then
    brew install trivy
  else
    # Linux: dùng script chính thức Aqua (không cần root nếu set BINDIR)
    curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh \
      | sh -s -- -b /usr/local/bin
  fi
fi
trivy --version   # xác nhận; DB vuln tự cập nhật lần chạy đầu
Step 1 — Detect language (scan scope)

Find lockfile to know the ecosystem: go.sum/go.mod (Go), package-lock.json/pnpm-lock.yaml (Node), requirements.txt/poetry.lock (Python). Skip node_modules, .next, .contentlayer, _archives, .git.

Step 2 — Scan (HIGH+CRITICAL first for speed)
trivy fs <dir> \
  --scanners vuln,misconfig,secret \
  --severity HIGH,CRITICAL \
  --skip-dirs '**/node_modules' --skip-dirs '**/.next' \
  --skip-dirs '**/.contentlayer' --skip-dirs '_archives' \
  --no-progress

Repo bonbon-ai: scan separately be and fe (each is a submodule). Prioritize --config trivy.yaml if the repo already has it.

Step 3 — Export full report
mkdir -p security
TPL=$(find $(brew --prefix trivy 2>/dev/null || echo /opt/homebrew) -name html.tpl 2>/dev/null | head -1)
trivy fs . <cờ skip-dirs như trên> --no-progress -f json     -o security/trivy-report.json
trivy fs . <cờ skip-dirs như trên> --no-progress -f template --template "@$TPL" -o security/trivy-report.html
Step 4 — Summarize & propose fixes

Count HIGH/CRITICAL per target, print table. Then propose (DO NOT auto-bump en masse if the submodule has uncommitted changes):

  • Easy dep bump (direct dep, edit manifest directly): e.g. python-multipart in requirements.txt.
  • Indirect dep: go get <pkg>@<ver> then go build ./... verify. Note go get may raise the directive go; if it exceeds the base image in the Dockerfile then bump FROM golang:X-alpine to match.
  • Misconfig DS-0002 (root user): add USER non-root to the Dockerfile (adduser -D alpine, useradd -m debian, or USER node for node-alpine image; remember chown write directories like volume/data).
  • Secret: if Trivy flags → rotate the key immediately, not just remove it from the file.
Step 5 — Re-scan to confirm

Re-run Step 2 on the fixed target, confirm remaining = NONE.

Scan OUTWARD — supply chain & brand (third key, keyless)

The two sections above both look INWARD at the project. Nothing looks OUTWARD: who is setting up a domain or package similar to your name to deceive users, or to inject a fake dependency into your own install command.

python3 fdk/tools/supply-watch.py <tên-thương-hiệu>            # sweep mặc định 7 TLD
python3 fdk/tools/supply-watch.py <tên> --tld com,dev --json   # cho CI
python3 fdk/tools/supply-watch.py --self-test

Generate variants deterministic, offline the following six patterns — character removal, character repetition, character swapping, adjacent-key typos (QWERTY keyboard), lookalike characters (o→0, l→1), adding a hyphen — then ask DNS which one is live. Plus a CT monitor that reads Certificate Transparency (crt.sh) to see whether any certificate was recently issued for a similar domain.

No API key needed, no .venv. Exit code: 0 clean · 2 findings detected. If crt.sh can't be reached it says SKIPPED, rather than declaring it clean.

Narrow ingestion from 7onez/cti-expert (workflow 08). Deliberately take only this piece: cti-expert is 121 ops + 78 MCP tools for investigating external threats, requiring .venv + API key + outbound network. Merging the whole block would drag key/network dependencies into a gateway that is currently keyless and able to run offline.

DYNAMIC scanning — verifying developer assumptions (complements Trivy)

Principle: Trivy (static) does NOT catch architecture/logic/runtime-configuration errors. The most severe vulnerabilities often lie in developer default assumptions — they must be verified with real requests, not taken on faith. "It runs" ≠ "it's secure".

Distilled from the 22/06/2026 incident: the payroll ETL API had no auth (auth was only at the web layer; the path /etl through nginx bypassed it) → anyone could curl retrieve salaries + PII of 3,637 employees; it was thought to be "internal" but a public domain devtingting.coteccons.vn (public IP) bridged it out to the entire internet. Trivy did not detect it — only curl/dig real tests revealed it.

"DON'T TRUST — verify" checklist (dev assumption → reality → how to verify)
  1. "The API behind the reverse proxy is protected because the web/UI has login." → FALSE: auth is usually only at the web layer; the proxy path (/etl, /api...) is called directly by the browser, so it BYPASSES login. → Verify: curl EACH API route DIRECTLY without cookies/tokens → it must 401. If 200+data = vulnerability. Auth must be at the API/proxy layer (e.g. nginx auth_request), NOT only at the UI.

    for p in data/stats/all report/export sync/status; do
      curl -k -o /dev/null -w "$p -> %{http_code}\n" https://HOST/etl/$p; done   # mong đợi 401
    
  2. "It's an internal server / private IP (192.168.x), so outsiders can't get in." → FALSE: a public domain / tailscale funnel / port-forward can bridge in. → Verify: dig +short <mọi subdomain khả dĩ> → does it have a public IP? Try curl from an external network. Do NOT trust "internal" — check DNS for real.

  3. "Opening CORS is a vulnerability / closing CORS is enough to be secure." → WRONG DIRECTION: CORS only blocks the browser from READING a cross-origin response. It does NOT block curl/script; it does NOT block WRITE CSRF (POST query-param / no-body = simple request → no preflight → server runs regardless of CORS). The real hole is usually no-auth + open port. Don't waste effort on CORS when the front door (auth) isn't locked.

  4. "Leaving the default config as-is is fine." → Check for default variables leaking into prod: CORS_ORIGINS still localhost:3000? secret/flag still at sample value? BIND_HOST accidentally 0.0.0.0?

    curl -k -D- -o /dev/null -H "Origin: http://localhost:3000" https://HOST/etl/health | grep -i access-control
    
  5. "Any branch deploys the same." → WRONG: CI (Jenkins) clones branch X but the server runs branch Y → drift. Merge conflicts can drop an entire block (e.g. networks: in compose → undefined network, deploy fails). → Verify: branch CI clones == branch currently running? git diff <ci-branch> <running-branch> -- docker-compose.yml .env* deploy/.

  6. "As long as paramiko/SSH connects, it's fine." → Transport(...) / AutoAddPolicy Does NOT verify host key → MITM steals password + files. Verify: must pin known_hosts + RejectPolicy.

  7. "Token/secret can be passed any way." → Token in URL ?token= → ends up in nginx/uvicorn access-log, Referer, history. Verify: secrets go via header/cookie, NOT via query string.

  8. "SELECT * for convenience." → Returns every column including PII (national ID/tax code/social insurance/salary) + search all-columns acts as an oracle for probing values. Verify: whitelist returned columns; search doesn't scan sensitive columns.

Trigger-conditions — which code behaviors MUST be scanned

Don't wait for anyone to remember to invoke the skill — if a diff falls into the table, scanning is mandatory (distilled from WorldFlowAI/everything-claude-code security-review):

Change just made Required Why
Add/modify auth, session, authorization Trivy + dynamic scan Token in localStorage is exposed to XSS, missing role check before sensitive operations — the authorization class of bugs is what Trivy doesn't see.
Accept user input (form, param, upload) Trivy + dynamic scan Input not validated by schema + file upload without size/type/extension limits is an entry point for SQLi/XSS/RCE.
Touch secret / credential / API key Trivy (secret scan) Key hardcoded in source or leaked into git history — must be in env var and platform secret, .env must be gitignored.
Open a new API endpoint Trivy + dynamic scan A new endpoint by default LACKS rate-limit + CSRF + permission check; error messages easily leak internal details/stack trace.
Payment / sensitive data Trivy + dynamic scan + manual review PII/money must not go into logs, errors must be generic; one flaw compromises the whole platform — err on the side of caution.
Expose app to public domain / change reverse proxy Dynamic scan The no-auth "internal" hole turns into internet-exposed exactly at that moment (the checklist assumes the dev above).

Not falling into the table → scanning at release cadence is enough. Self-check question: "does this diff do one of the 6 things above?" — answerable in under a minute. User says "is there a vulnerability", "is it safe yet" → always a trigger.

Branches

ID Kind Guard Behavior Skip / failure Rejoin
B01 conditional_required repo bonbon-ai scan separately be and fe (each is a submodule); deploy only pushes those 2 submodules other repo → scan . W04
B02 conditional_required repo already has trivy.yaml prioritize --config trivy.yaml none → default skip-dirs flag W04
B03 user_optional user wants to inspect the supply chain / brand supply-watch.py <tên> sweep 7 TLDs + CT monitor not requested → skip end
B04 conditional_required finding has been reviewed and accepted write .trivyignore (1 ID/line + reason + date), do not remove from report — W06
B05 conditional_required Trivy flags secret rotate the key immediately, not just remove it from the file — W06

Validation and stopping

Deterministic: rc/output of Trivy (re-scan remaining = NONE), real HTTP code of curl (an API route without a token must be 401), dig real, git diff branch, rc supply-watch.py. Fix only commits after build/verify is green. Needs a human: decision to accept a finding into .trivyignore, manual review of payment flows/sensitive data. Stop when the re-scan is clean and every assumption in the checklist has evidence; do not conclude "safe" from Trivy alone.

Examples

  • Positive: "security scan the bonbon-ai repo" → Trivy already present → scan separately be, fe → 2 HIGH: python-multipart in requirements.txt + DS-0002 root user → bump dep + add USER node → build green → re-scan remaining = NONE; dynamic scan curl /etl/data/stats/all without token returns 401.
  • Boundary/failure: Trivy is clean but curl directly /etl/report/export without cookie returns 200 + salary data → auth-bypass vulnerability, report as severe even though the static report is clean (RULE-01); dig +short subdomain resolves to a public IP → "internal" is wrong.
  • Boundary: supply-watch.py acme when crt.sh does not respond → print SKIPPED for CT monitor, do not report clean.

Origin

  • Absorb 2026-07-17 (adapt_mode: dissolve, T-260717-02): trigger-conditions table distilled from WorldFlowAI/everything-claude-code (skills/security-review/SKILL.md — When to Activate + 10 checklist groups). Clone depth-1 in scratchpad/, do not vendor bytes.