{"id":"17693c70-52c2-4903-a8d7-47fa343cf27c","entityType":"agent","slug":"clawhub-athola-nm-pensive-harden","name":"harden","canonicalUrl":"https://www.xpersona.co/agent/clawhub-athola-nm-pensive-harden","canonicalPath":"/agent/clawhub-athola-nm-pensive-harden","generatedAt":"2026-10-11T21:00:28.138Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T16:09:39.775Z","emptyReason":null},"description":"Applies NIST/CWE security hardening to Python and Rust code Skill: harden Owner: athola Summary: Applies NIST/CWE security hardening to Python and Rust code Tags: latest:1.9.19 Version history: v1.9.19 | 2026-08-26T13:18:46.218Z | user Release v1.9.19 v1.9.17 | 2026-07-30T05:39:00.969Z | user Release v1.9.17 v1.9.16 | 2026-07-14T19:55:43.255Z | user Release v1.9.16 v1.9.14 | 2026-06-30T18:04:05.262Z | user Release v1.9.14 v1.9.13 | 2026-06-27T16:22:07.173Z | user Release v1.9","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s17emme0e2m3cpf7k2jvp3a84984b8z9:nm-pensive-harden","sourceUrl":"https://clawhub.ai/athola/nm-pensive-harden","homepage":"https://clawhub.ai/athola/skills/nm-pensive-harden","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/athola/nm-pensive-harden","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/athola/skills/nm-pensive-harden","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":60,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Applies NIST/CWE security hardening to Python and Rust code Skill: harden Owner: athola Summary: Applies NIST/CWE security hardening to Python and Rust code Tag"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T16:09:39.775Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T16:09:39.775Z","emptyReason":null},"stars":null,"forks":null,"downloads":1031,"likes":null,"task":null,"library":null,"packageName":null,"latestVersion":"1.9.19","tractionLabel":"1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T16:09:39.759Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T16:09:39.775Z","lastCrawledAt":"2026-10-11T16:09:39.759Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T16:09:39.759Z","lastVerifiedAt":null,"highlights":[{"version":"1.9.19","createdAt":"2026-08-26T13:18:46.218Z","changelog":"Release v1.9.19","fileCount":9,"zipByteSize":23321},{"version":"1.9.17","createdAt":"2026-07-30T05:39:00.969Z","changelog":"Release v1.9.17","fileCount":9,"zipByteSize":23205},{"version":"1.9.16","createdAt":"2026-07-14T19:55:43.255Z","changelog":"Release v1.9.16","fileCount":9,"zipByteSize":23344},{"version":"1.9.14","createdAt":"2026-06-30T18:04:05.262Z","changelog":"Release v1.9.14","fileCount":9,"zipByteSize":23394},{"version":"1.9.13","createdAt":"2026-06-27T16:22:07.173Z","changelog":"Release v1.9.13","fileCount":9,"zipByteSize":23552},{"version":"1.9.12","createdAt":"2026-06-19T03:17:14.134Z","changelog":"Release v1.9.12","fileCount":9,"zipByteSize":23297},{"version":"1.0.0","createdAt":"2026-06-18T14:12:06.953Z","changelog":"Initial release of the harden skill for NIST/CWE-aligned security hardening in Python and Rust codebases. - Scans entire repositories for security vulnerabilities and forward-facing threats, not just diffs. - Maps findings to NIST SSDF practices and CWEs with citation-backed remediation proposals. - Modular workflow with progressive loading: Python, Rust, cross-cutting concerns, and frontier checks. - Guides users through proposal approval: apply, file as issue, defer, or reject. - Applies and validates approved remediations, reverting on gate failures and generating comprehensive reports. - Designed for periodic audits, release pre-checks, and baseline onboarding security reviews.","fileCount":9,"zipByteSize":23404}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17emme0e2m3cpf7k2jvp3a84984b8z9:nm-pensive-harden","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-harden/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-harden/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-harden/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-harden/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-harden/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-harden/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T21:00:28.135Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-harden/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-harden/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-harden/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-athola-nm-pensive-harden/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T16:09:39.775Z","emptyReason":null},"readme":"Skill: harden\n\nOwner: athola\n\nSummary: Applies NIST/CWE security hardening to Python and Rust code\n\nTags: latest:1.9.19\n\nVersion history:\n\nv1.9.19 | 2026-08-26T13:18:46.218Z | user\n\nRelease v1.9.19\n\nv1.9.17 | 2026-07-30T05:39:00.969Z | user\n\nRelease v1.9.17\n\nv1.9.16 | 2026-07-14T19:55:43.255Z | user\n\nRelease v1.9.16\n\nv1.9.14 | 2026-06-30T18:04:05.262Z | user\n\nRelease v1.9.14\n\nv1.9.13 | 2026-06-27T16:22:07.173Z | user\n\nRelease v1.9.13\n\nv1.9.12 | 2026-06-19T03:17:14.134Z | user\n\nRelease v1.9.12\n\nv1.0.0 | 2026-06-18T14:12:06.953Z | auto\n\nInitial release of the harden skill for NIST/CWE-aligned security hardening in Python and Rust codebases.\n\n- Scans entire repositories for security vulnerabilities and forward-facing threats, not just diffs.\n- Maps findings to NIST SSDF practices and CWEs with citation-backed remediation proposals.\n- Modular workflow with progressive loading: Python, Rust, cross-cutting concerns, and frontier checks.\n- Guides users through proposal approval: apply, file as issue, defer, or reject.\n- Applies and validates approved remediations, reverting on gate failures and generating comprehensive reports.\n- Designed for periodic audits, release pre-checks, and baseline onboarding security reviews.\n\nArchive index:\n\nArchive v1.9.19: 9 files, 23321 bytes\n\nFiles: modules/cross-cutting.md (5415b), modules/frontier-checks.md (5056b), modules/nist-controls.md (4262b), modules/proposal-shape.md (5761b), modules/python-checks.md (7917b), modules/rust-checks.md (5491b), skill-card.md (2323b), SKILL.md (10269b), _meta.json (137b)\n\nFile v1.9.19:SKILL.md\n\n---\nname: harden\ndescription: Applies NIST/CWE security hardening to Python and Rust code\nversion: 1.9.8\ntriggers:\n  - security\n  - hardening\n  - nist\n  - supply-chain\n  - python\n  - rust\n  - cwe\n  - auditing code for vulnerabilities or proposing concrete security remediations\nmetadata: {\"openclaw\": {\"homepage\": \"https://github.com/athola/claude-night-market/tree/master/plugins/pensive\", \"emoji\": \"\\ud83d\\udd12\", \"requires\": {\"config\": [\"night-market.pensive:safety-critical-patterns\", \"night-market.pensive:rust-review\", \"night-market.pensive:bug-review\", \"night-market.pensive:tiered-audit\", \"night-market.pensive:blast-radius\", \"night-market.leyline:supply-chain-advisory\", \"night-market.leyline:authentication-patterns\", \"night-market.leyline:content-sanitization\", \"night-market.abstract:hook-authoring\", \"night-market.imbue:proof-of-work\"]}}}\nsource: claude-night-market\nsource_plugin: pensive\n---\n\n> **Night Market Skill** — ported from [claude-night-market/pensive](https://github.com/athola/claude-night-market/tree/master/plugins/pensive). For the full experience with agents, hooks, and commands, install the Claude Code plugin.\n\n\n# Harden Codebase Skill\n\nActive security hardening — scan the existing repository for\nvulnerabilities and forward-facing threats, then propose concrete\nremediations the user can approve, defer, or file.\n\nThis skill is the engine behind `/harden`. It complements the\nClaude Code built-in `/security-review` (which scans the pending\ndiff) by sweeping the whole repository against citation-backed\nchecks rather than line-level review of in-flight code.\n\n## When To Use\n\n- Quarterly security-posture audits.\n- Before tagging a release that touches sensitive code paths.\n- After a published advisory affects the language ecosystem.\n- When onboarding a new repository and want a baseline.\n- After integrating a new dependency or upstream service.\n\n## When NOT To Use\n\n- Pending-diff review on a single PR. Use `/security-review`.\n- Architecture-level threat modeling. Use `attune:war-room`\n  with a security-focused panel.\n- Cryptographic protocol review. The skill flags suspect crypto\n  but does not propose protocol fixes (specialist work).\n- One-off bug hunting. Use `pensive:bug-review`.\n\n## Required TodoWrite Items\n\n1. `harden:discovery` — inventory languages, build files, hooks,\n   CI workflows\n2. `harden:scan-python` — run python-checks.md detectors when\n   Python is present\n3. `harden:scan-rust` — run rust-checks.md detectors when Rust\n   is present\n4. `harden:scan-cross-cutting` — run cross-cutting.md detectors\n   (deps, secrets, SBOM, CI)\n5. `harden:scan-frontier` — run frontier-checks.md (PQC, LLM\n   supply chain, sandboxing)\n6. `harden:nist-mapping` — map findings to NIST SSDF practices\n7. `harden:proposals` — for each finding above the threshold,\n   draft a concrete remediation per `modules/proposal-shape.md`\n8. `harden:approval-gate` — present proposals to the user for\n   apply / file / defer / reject\n9. `harden:apply-and-validate` — apply approved proposals as\n   discrete commits, re-run gates, capture evidence\n10. `harden:report` — write `reviews/harden-<date>.md` and\n    optionally post to Discussions\n\n## Progressive Loading\n\nLoad modules based on what the discovery step finds.\n\n| Detected | Load |\n|----------|------|\n| Python files (`*.py`, `pyproject.toml`) | `modules/python-checks.md` |\n| Rust files (`*.rs`, `Cargo.toml`) | `modules/rust-checks.md` |\n| Any | `modules/nist-controls.md` (citation backbone) |\n| Any | `modules/cross-cutting.md` (deps, secrets, CI) |\n| LLM SDK use (`anthropic`, `openai`), MCP server, post-quantum surface | `modules/frontier-checks.md` |\n| Any with proposals enabled | `modules/proposal-shape.md` |\n\nThe module hub keeps the SKILL.md itself under the\n`estimated_tokens: 1100` budget. Detail lives in the modules.\n\n## Core Workflow\n\n### Phase 1 — Discovery\n\nInventory the repo without modifying anything:\n\n```bash\n# Languages and build files\nfind . -type f \\( -name '*.py' -o -name '*.rs' -o -name '*.sh' \\) \\\n  | head -200 > /tmp/harden-langs.txt\n\n# Build manifests\nls pyproject.toml Cargo.toml package.json go.mod 2>/dev/null\n\n# CI workflows and pre-commit\nls .github/workflows/ .pre-commit-config.yaml 2>/dev/null\n\n# Hooks and Dockerfiles\nfind . -path ./node_modules -prune -o -type f \\\n  \\( -name 'hooks.json' -o -name 'Dockerfile*' \\) -print\n```\n\nDispatch `/discovery-prefilter` if the repo has > 5000 source files\nto bound the scan.\n\n### Phase 2 — Citation-backed scan\n\nFor each detected language, load the matching module and run its\ndetector list. Each detector outputs findings with the schema\ndefined in `modules/proposal-shape.md`. The citation column is\nmandatory: a finding without a NIST/CWE reference is downgraded\nto \"advisory\" and not eligible for active proposal.\n\n### Phase 3 — NIST mapping\n\nGroup findings by SSDF practice (PW.4, PW.8, RV.1, etc.) and CWE\nID. The mapping table lives in `modules/nist-controls.md`. The\nreport's executive summary references SSDF practice coverage so\nthe audit is comparable across runs.\n\n### Phase 4 — Proposal generation\n\nFor each finding above the configured severity threshold, draft a\nconcrete remediation per `modules/proposal-shape.md`:\n\n- Specific files and lines touched\n- Diff or config snippet (not \"consider doing X\")\n- Blast-radius assessment via `pensive:blast-radius`\n- Reversal plan: how to revert if the change breaks behavior\n- Test that should pass after the change\n\n### Phase 5 — Approval gate\n\nPresent proposals one at a time via `AskUserQuestion`. Default\noptions: **apply**, **file as issue**, **defer to backlog**,\n**reject**. Auto-apply is opt-in via the `--auto-apply` flag and\nrespects a per-finding severity threshold.\n\n### Phase 6 — Apply and validate\n\nApply each approved proposal as a discrete commit:\n\n```bash\ngit add <touched files>\ngit commit -m \"harden: <finding-id> <one-line summary>\"\n```\n\nAfter each apply, re-run the project gates:\n\n```bash\nmake test --quiet && make lint && make type-check\n```\n\nIf a gate fails, revert the commit (`git revert HEAD --no-edit`)\nand downgrade the finding to \"needs human design.\"\n\n### Phase 7 — Report\n\nWrite `reviews/harden-<date>.md` with:\n\n- Executive summary (SSDF practice coverage, CWE distribution)\n- Findings table grouped by severity\n- Per-finding detail: detection signal, citation, proposal, status\n- Disposition table (applied / filed / deferred / rejected)\n- Re-run instructions\n\nIf running inside a PR context, post the executive summary as a\ncomment via `abstract:post_review_insights`.\n\n## Severity Classification\n\n| Severity | Definition | Default disposition |\n|----------|------------|---------------------|\n| **CRITICAL** | Active exploit path, RCE, credential leak | apply or file immediately |\n| **HIGH** | Plausible exploit, missing defense-in-depth on attack surface | propose for apply |\n| **MEDIUM** | Best-practice gap, hardening opportunity | propose for apply with `--auto-apply medium` |\n| **LOW** | Style/documentation gap with security flavor | file as issue |\n| **ADVISORY** | Pattern detected without exploit narrative | report only |\n\n## Output Format\n\n```markdown\n# Hardening Report — <date>\n\n## Executive Summary\n\n- Codebase: <repo> @ <sha>\n- Languages scanned: Python (X files), Rust (Y files)\n- NIST SSDF practices covered: PW.4, PW.7, PW.8, RV.1, RV.2\n- CWE Top 25 hits: <count> across <distinct CWEs>\n- Disposition: <N> applied, <N> filed, <N> deferred, <N> rejected\n\n## Findings\n\n| ID | Severity | Citation | File:Line | Disposition |\n|----|----------|----------|-----------|-------------|\n| H1 | CRITICAL | CWE-502, NIST SSDF PW.7 | `src/x.py:45` | applied (commit abc123) |\n| H2 | HIGH | CWE-89, NIST SSDF PW.4 | `src/y.py:120` | filed (#456) |\n\n## Per-finding detail\n\n### H1 — Unsafe deserialization\n\n**Citation:** CWE-502 (Deserialization of Untrusted Data),\nNIST SSDF PW.7 (Review and analyze human-readable code).\n\n**Detection signal:**\n- File: `src/x.py:45`\n- Pattern: <module>.loads(user_supplied_input)\n- Reachability: untrusted, comes from request body\n\n**Proposal:** ...\n\n**Blast radius:** ...\n\n**Reversal plan:** ...\n```\n\n## Safety Rails\n\n- **Never apply without approval.** Even with `--auto-apply`,\n  CRITICAL findings always prompt.\n- **One finding per commit.** Reversals are per-finding, not\n  per-batch.\n- **Re-run gates after each apply.** A gate failure reverts the\n  commit and downgrades the finding.\n- **Citation is mandatory.** Findings without a NIST/CWE/RustSec\n  reference are advisory only and skip the apply phase.\n- **Read-only on first run.** First invocation defaults to\n  `--report-only` until the user has reviewed at least one\n  report and explicitly opts into proposals.\n\n## Integration\n\nThe skill composes (rather than re-implements):\n\n- `pensive:rust-review` — full Rust audit when Rust is present\n- `pensive:bug-review` — bug-hunting backbone\n- `pensive:safety-critical-patterns` — NASA Power-of-10 adapted\n- `pensive:tiered-audit` — three-tier discipline (`--tier 1/2/3`)\n- `pensive:blast-radius` — change-impact assessment for proposals\n- `leyline:supply-chain-advisory` — dependency posture\n- `leyline:authentication-patterns` — auth/credential review\n- `leyline:content-sanitization` — input handling\n- `abstract:hook-authoring` — hook-event security\n- `imbue:proof-of-work` — evidence discipline for findings\n\n## Exit Criteria\n\n- [ ] Discovery output lists every language and build manifest\n      detected in the repo.\n- [ ] Each finding carries a CWE or NIST SSDF citation; the\n      report executive summary lists the SSDF practice coverage.\n- [ ] Each finding above the severity threshold has a concrete\n      proposal (file, diff or config snippet, blast radius,\n      reversal plan, expected-passing test).\n- [ ] No proposal was applied without explicit user approval\n      (or without an `--auto-apply` flag covering its severity).\n- [ ] Each applied proposal is its own commit, reversal-friendly.\n- [ ] After every apply, the project gates were re-run; any\n      gate failure reverted the commit and downgraded the\n      finding.\n- [ ] `reviews/harden-<date>.md` exists and lists every finding\n      with a disposition (applied / filed / deferred / rejected /\n      advisory).\n\nFile v1.9.19:_meta.json\n\n{\n  \"ownerId\": \"kn7d107jg9jv602h9ytsegydq184a42s\",\n  \"slug\": \"nm-pensive-harden\",\n  \"version\": \"1.9.19\",\n  \"publishedAt\": 1787750326218\n}\n\nFile v1.9.19:modules/cross-cutting.md\n\n# Cross-Cutting Hardening Checks\n\nChecks that apply regardless of the source language: dependency\nposture, secret hygiene, CI/CD chain, container shape, and the\nSBOM.\n\n## Dependency posture (composes leyline:supply-chain-advisory)\n\n| ID | Check | CWE / NIST | Detection |\n|----|-------|------------|-----------|\n| DEP01 | Lockfile committed | PW.4 | absence of `uv.lock` / `Cargo.lock` / `package-lock.json` |\n| DEP02 | Dependency scanner runs in CI | RV.1 | no `pip-audit`/`cargo audit`/`npm audit` step in workflows |\n| DEP03 | Known-bad versions blocked | CWE-829 | `leyline:supply-chain-advisory` blocklist not consulted |\n| DEP04 | Auto-update bot configured | RV.1 | no `dependabot.yml` / `renovate.json` |\n| DEP05 | Direct deps pinned to exact versions | CWE-494 | `^1.2` / `~1.2` / `1.2.*` for security-critical deps |\n| DEP06 | Hash-pinned for top-tier supply-chain trust | CWE-494 | `--require-hashes` not used in `pip` / `requirements.txt` |\n| DEP07 | License policy enforced | none | no `cargo deny` license rules / no `pip-licenses` check |\n\n## Secret hygiene\n\n| ID | Check | CWE | Detection |\n|----|-------|-----|-----------|\n| SEC01 | Pre-commit secret scanner installed | CWE-798 | no `gitleaks` / `trufflehog` / `talisman` in `.pre-commit-config.yaml` |\n| SEC02 | `.env` files git-ignored | CWE-200 | `.env` tracked or unmatched in `.gitignore` |\n| SEC03 | Long-lived secrets in CI | CWE-798 | `secrets.SOME_KEY` used without `if: github.event_name != 'pull_request'` |\n| SEC04 | OIDC publishing configured | CWE-798 | PyPI/Cargo publish step uses `password:` rather than OIDC `id-token: write` |\n| SEC05 | Audit trail for secret access | PW.7 | repo settings: secret-access logs not retained |\n| SEC06 | Sealed-secrets / secret manager | CWE-798 | secrets baked into config files instead of fetched from a manager |\n\n## CI/CD chain (GitHub Actions example)\n\n| ID | Check | NIST SSDF | Detection |\n|----|-------|-----------|-----------|\n| CI01 | Third-party actions pinned by SHA, not tag | PW.4 | `uses: foo/bar@v1` instead of `@<full SHA>` |\n| CI02 | `permissions:` block per workflow | PW.4 | top-level `permissions:` missing or `permissions: write-all` |\n| CI03 | `GITHUB_TOKEN` minimum scope | PW.4 | default permissions used when `contents: read` would suffice |\n| CI04 | Concurrency cancel for stale runs | RV.2 | no `concurrency.cancel-in-progress: true` |\n| CI05 | Workflow dispatch requires approval for protected branches | PW.4 | branch protection allows direct dispatch |\n| CI06 | SLSA provenance generated for releases | RV.2 | release workflow does not invoke `slsa-framework/slsa-github-generator` |\n| CI07 | SBOM generated and attached to releases | RV.2 | release workflow lacks `cyclonedx`/`syft`/`spdx-sbom-generator` step |\n\n## Container hardening (when Dockerfiles exist)\n\n| ID | Check | CWE | Detection |\n|----|-------|-----|-----------|\n| CO01 | Non-root `USER` set | CWE-269 | `USER root` or `USER` directive missing |\n| CO02 | `FROM` is digest-pinned | CWE-494 | `FROM ubuntu:22.04` instead of `FROM ubuntu@sha256:...` |\n| CO03 | Distroless or slim base for production | PW.4 | `FROM ubuntu:latest` / `FROM debian:latest` for runtime image |\n| CO04 | Read-only root filesystem in compose | CWE-269 | `read_only: true` not set |\n| CO05 | seccomp/apparmor profile referenced | CWE-269 | runtime config lacks profile |\n| CO06 | Multi-stage build to drop build deps | CWE-665 | single-stage `FROM` keeps `gcc`, `make`, etc. in runtime |\n| CO07 | `HEALTHCHECK` defined | none | no liveness signal (operational hygiene) |\n\n## SBOM and provenance\n\n```bash\n# CycloneDX SBOM for the whole repo\nsyft . -o cyclonedx-json > sbom.cdx.json\n\n# SPDX SBOM (alternative format)\nsyft . -o spdx-json > sbom.spdx.json\n\n# Verify against the in-toto attestation if released\ncosign verify-attestation --type slsaprovenance \\\n  --certificate-identity-regexp '.*' --certificate-oidc-issuer-regexp '.*' \\\n  ghcr.io/<org>/<image>:<tag>\n```\n\nThe hardening report includes an SBOM-coverage row: present /\nabsent for each release artifact in the repo.\n\n## Pre-commit security suite\n\nThe skill proposes adding (or extending) `.pre-commit-config.yaml`\nwith:\n\n```yaml\nrepos:\n  - repo: https://github.com/PyCQA/bandit\n    rev: 1.7.10\n    hooks:\n      - id: bandit\n        args: [\"-c\", \"pyproject.toml\"]\n        additional_dependencies: [\"bandit[toml]\"]\n  - repo: https://github.com/gitleaks/gitleaks\n    rev: v8.21.2\n    hooks:\n      - id: gitleaks\n  - repo: https://github.com/Yelp/detect-secrets\n    rev: v1.5.0\n    hooks:\n      - id: detect-secrets\n        args: [\"--baseline\", \".secrets.baseline\"]\n```\n\nIf `cargo` is on PATH:\n\n```yaml\n  - repo: local\n    hooks:\n      - id: cargo-deny\n        name: cargo deny\n        entry: cargo deny check\n        language: system\n        files: 'Cargo\\.(toml|lock)$'\n```\n\n## Severity defaults\n\n| Family | Default | Justification |\n|--------|---------|---------------|\n| DEP04, DEP07, CI07, CO07 | LOW | operational hygiene; no exploit narrative |\n| DEP01, DEP02, SEC01, SEC02, CI02, CI03, CO01, CO02 | MEDIUM | one defense-in-depth layer missing |\n| DEP03, SEC03, SEC04, CI01, CI06, CO03 | HIGH | exploitable supply-chain or privilege issue |\n| SEC03 with leaked active credential | CRITICAL | active exploit path |\n\nA finding can be promoted from default with evidence (e.g.,\nDEP01 promoted to HIGH if the lockfile is missing AND auto-merge\nis enabled on dep PRs).\n\nFile v1.9.19:modules/frontier-checks.md\n\n# Frontier Hardening Checks (2025-2026)\n\nForward-facing checks that defend against threats just emerging\nin production. Findings here are usually MEDIUM by default\nbecause exploitation is non-trivial; promote to HIGH when the\ncodebase has a high-value attack surface (auth provider, signing\nservice, data plane).\n\n## Post-quantum migration readiness\n\nThe NSA CNSA 2.0 timeline targets quantum-resistant crypto for\nNSS by 2030; PCI DSS 4.0.1 expects an inventory by 2026. Most\napplication code is not the right place to swap algorithms, but\nthe *crypto-agility* posture is.\n\n| ID | Check | Citation | Detection |\n|----|-------|----------|-----------|\n| PQ01 | Signing/verification has a single hard-coded algorithm | NIST IR 8547 | `algorithms = [\"RS256\"]` or `algorithms = [\"EdDSA\"]` literal in JWT/JWS code |\n| PQ02 | Algorithm selection driven by config, not code | NIST IR 8547 | move the algorithm list behind a `signing_algorithms` config field |\n| PQ03 | Inventory of crypto APIs in the repo | NIST CNSA 2.0 | no `docs/crypto-inventory.md` or equivalent |\n| PQ04 | TLS clients accept algorithm downgrade silently | CWE-757 | `requests` / `reqwest` defaults without minimum-TLS pin |\n\nThe proposal for PQ02 is usually a small refactor: move\n`algorithms = [\"EdDSA\"]` into a config table the operator can\noverride. The skill does not propose ML-DSA / Falcon migration\nin application code (still specialist work).\n\n## LLM and agentic supply chain\n\nA new failure mode in 2025: AI assistants suggest dependencies\nthat look plausible but do not exist (or are typosquats). The\nchecks below defend the development pipeline itself.\n\n| ID | Check | Citation | Detection |\n|----|-------|----------|-----------|\n| LLM01 | Index pinning to defeat dependency confusion | OWASP LLM Top 10 #08 | `pyproject.toml` lacks `[[tool.uv.index]]` priority order |\n| LLM02 | New deps require human review | OWASP LLM Top 10 #08 | no CI rule blocking auto-merge on dep PRs |\n| LLM03 | LLM SDK calls validate role/instruction boundaries | OWASP LLM Top 10 #01 | system prompt concatenated with user input without separator/role |\n| LLM04 | Tool-use response sanitization | OWASP LLM Top 10 #02 | tool output rendered to UI/terminal without escape |\n| LLM05 | MCP server allowlist of tools | OWASP LLM Top 10 #02 | MCP config mounts every tool from a server (no allowlist) |\n| LLM06 | Agent action audit trail | OWASP LLM Top 10 #06 | no log of tool invocations with inputs |\n\n## Sandbox / isolation posture\n\nFor codebases that execute user-supplied or AI-supplied code:\n\n| ID | Check | Why | Today's option |\n|----|-------|-----|----------------|\n| SB01 | User code runs in same process as host | host privilege escalation | Pyodide WASM (Python), wasmtime (Rust) |\n| SB02 | Network egress unrestricted from sandbox | data exfiltration | gVisor egress policy, NetworkPolicy in K8s |\n| SB03 | Filesystem capabilities ambient | path-based attacks | `cap-std` (Rust), bind-mount only required dirs |\n| SB04 | Resource limits absent | DoS via runaway workload | cgroup `memory.max`, `cpu.max`; `prlimit` in containers |\n\n## eBPF / runtime security hooks\n\nProduction codebases benefit from runtime monitoring even when\nthe static defenses are good. The skill flags absence:\n\n| ID | Check | Tool | What it catches |\n|----|-------|------|-----------------|\n| RT01 | Runtime detection layer present | Falco / Tetragon / Tracee | unexpected syscalls, container escapes |\n| RT02 | App emits structured audit events | OpenTelemetry traces with semantic conventions | post-incident reconstruction |\n| RT03 | Deployment includes seccomp/apparmor profile | runtime config | exploit blast-radius capping |\n\n## Differential-privacy / PETs awareness\n\nFor codebases that handle aggregable user data (analytics, ML\ntraining, telemetry):\n\n| ID | Check | Citation | Signal |\n|----|-------|----------|--------|\n| DP01 | Aggregations expose per-user values without noise | NIST SP 800-188 | counts/means published without DP budget |\n| DP02 | Logs retain raw PII beyond retention window | GDPR Art. 5 | log retention config absent or > 30 days for PII fields |\n\n## Memory-safety migration triage (when C/C++ is present)\n\nPer CISA's \"Secure by Design\" pledge and the ONCD memory-safety\nreport (Feb 2024), new code in safety-critical contexts should\nbe in a memory-safe language by default. The skill flags the\nopportunity, not the migration:\n\n| ID | Check | Signal | Proposal |\n|----|-------|--------|----------|\n| MS01 | C/C++ code paths handle untrusted input | parser, network code in C/C++ | rewrite or wrap behind a Rust shim |\n| MS02 | C-style string handling | `strcpy`, `sprintf`, `gets` | move to Rust or use `safestr`/`absl::Cord` |\n\n## Output\n\nFindings here use the same schema as the other modules. Severity\nis **MEDIUM** by default; promote to HIGH when:\n\n- The repo is an auth/signing/credentialing service (PQ findings)\n- The repo ships an MCP server or agent harness (LLM findings)\n- The repo has untrusted-code-exec posture (SB findings)\n- The repo handles regulated PII (DP findings)\n\nFile v1.9.19:modules/nist-controls.md\n\n# NIST and CWE Citation Backbone\n\nEvery finding in a hardening report carries a citation. This\nmodule is the lookup table.\n\n## NIST SSDF (SP 800-218) practice mapping\n\nThe Secure Software Development Framework defines four practice\ngroups: Prepare the Organization (PO), Protect Software (PS),\nProduce Well-Secured Software (PW), Respond to Vulnerabilities\n(RV). Findings map to PW and RV most often.\n\n| Practice | What it requires | Detector signal |\n|----------|------------------|-----------------|\n| PW.4 | Reuse existing well-secured software | dependencies pinned, scanned, attested |\n| PW.5 | Create source code aligned with secure practices | linter enforces auth/crypto/serialization rules |\n| PW.6 | Configure compilation, build processes, links | RUSTFLAGS hardening, Python `-W error`, reproducible builds |\n| PW.7 | Review and analyze human-readable code | SAST run in CI; findings tracked |\n| PW.8 | Test executable code | fuzz coverage, mutation tests, property tests |\n| PW.9 | Configure software with secure default settings | yaml SafeLoader, TLS verify on, autoescape on |\n| RV.1 | Identify, confirm vulnerabilities on a continuous basis | dependency scanner runs on every push |\n| RV.2 | Assess, prioritize, remediate vulnerabilities | severity policy, SLA per severity |\n| RV.3 | Analyze vulnerabilities to identify root causes | post-incident notes feed PW.4-9 |\n\nThe skill's executive summary lists each practice and whether the\ncodebase has at least one detector firing for it. Coverage <80%\nof PW.4-PW.9 is itself a finding (RV.1 unmet).\n\n## CWE Top 25 (2024) mapping\n\nThe skill prioritizes detectors that map to the CWE Top 25 most\ndangerous software weaknesses. Per-finding citations name the\nspecific CWE, not just \"Top 25.\"\n\n| CWE | Title | Languages most often hit |\n|-----|-------|--------------------------|\n| CWE-79 | Cross-site Scripting | Python, JS |\n| CWE-787 | Out-of-bounds Write | Rust unsafe, C/C++ FFI |\n| CWE-89 | SQL Injection | Python, Rust |\n| CWE-352 | CSRF | Python web frameworks |\n| CWE-22 | Path Traversal | All |\n| CWE-125 | Out-of-bounds Read | Rust unsafe, C/C++ FFI |\n| CWE-78 | OS Command Injection | Python (subprocess), shell scripts |\n| CWE-416 | Use After Free | Rust unsafe, C/C++ |\n| CWE-862 | Missing Authorization | Web layer |\n| CWE-434 | Unrestricted File Upload | Web layer |\n| CWE-94 | Code Injection | Python (eval/exec), template engines |\n| CWE-20 | Improper Input Validation | All |\n| CWE-77 | Command Injection | All shell-out paths |\n| CWE-287 | Improper Authentication | Auth layer |\n| CWE-269 | Improper Privilege Management | Container, sudo |\n| CWE-502 | Deserialization of Untrusted Data | Python, Java |\n| CWE-200 | Exposure of Sensitive Information | Logs, errors, telemetry |\n| CWE-863 | Incorrect Authorization | Web layer |\n| CWE-918 | Server-Side Request Forgery | URL fetchers |\n| CWE-119 | Improper Restriction of Operations within Memory Buffer | Rust unsafe, C/C++ |\n| CWE-476 | NULL Pointer Dereference | Rust unsafe, C/C++ |\n| CWE-798 | Use of Hard-coded Credentials | All |\n| CWE-190 | Integer Overflow or Wraparound | All |\n| CWE-400 | Uncontrolled Resource Consumption | All |\n| CWE-306 | Missing Authentication for Critical Function | Web/API layer |\n\n## OWASP ASVS level targets\n\nFindings track the ASVS level they aim at:\n\n| Level | Target | Skill default |\n|-------|--------|---------------|\n| L1 | Opportunistic attacker | always |\n| L2 | Targeted attacker | when secrets-bearing config detected |\n| L3 | Determined attacker | only on `--focus all` with `--strict` |\n\n## RustSec advisory database\n\nFor Rust findings, cite the specific advisory ID\n(RUSTSEC-YYYY-NNNN). The `cargo audit` JSON output contains\nthese directly. Use them in the proposal's reversal plan to\nexplain *why* the upgrade is required.\n\n## How findings cite\n\nEach finding's `Citation:` line names:\n\n1. Primary CWE (always)\n2. NIST SSDF practice (always; pick the closest match)\n3. Optional: OWASP ASVS section, RustSec ID, PEP number, CVE\n\nExample:\n\n```\nCitation: CWE-502 (Deserialization of Untrusted Data),\nNIST SSDF PW.7 (Review and analyze human-readable code),\nOWASP ASVS V5.5 (Deserialization Prevention).\n```\n\nA finding with no primary CWE cannot be classified above\nADVISORY severity.\n\nFile v1.9.19:modules/proposal-shape.md\n\n# Proposal Shape\n\nEvery proposed remediation in a hardening report follows this\nschema. The schema is not optional: a finding without a complete\nproposal cannot be applied (the user can still choose to file or\ndefer it).\n\n## Required fields\n\n| Field | Purpose |\n|-------|---------|\n| `id` | Stable identifier across runs (e.g., `H7`, `PY03`) |\n| `severity` | CRITICAL / HIGH / MEDIUM / LOW / ADVISORY |\n| `citation` | Primary CWE plus NIST SSDF practice (mandatory) |\n| `file` | Single file the proposal touches (multi-file proposals split into siblings) |\n| `lines` | Affected line range, e.g., `42-58` |\n| `detection_signal` | What pattern the scanner saw (in safe-to-quote form) |\n| `proposal` | One-paragraph description of the fix |\n| `diff` | Concrete diff or config snippet, not \"consider doing X\" |\n| `blast_radius` | low / medium / high — see below |\n| `reversal_plan` | Exact command to revert and the conditions to reapply |\n| `expected_test` | Test path that should pass after the change |\n\n## Severity to default disposition\n\n| Severity | Default disposition |\n|----------|---------------------|\n| CRITICAL | apply or file immediately; never advisory |\n| HIGH | propose for apply with prompt |\n| MEDIUM | propose for apply only when `--auto-apply medium` |\n| LOW | file as issue by default |\n| ADVISORY | report only; never proposed |\n\nCRITICAL findings always prompt even under `--auto-apply`.\n\n## Blast radius scale\n\nThe proposal queries `Skill(pensive:blast-radius)` for the\nchange-impact graph and reports one of:\n\n| Tier | Definition |\n|------|------------|\n| **low** | Single file; no public API change; no signature change; no behavior visible to callers |\n| **medium** | Multiple files OR public API addition (new param with default, new method) OR test-only behavior change |\n| **high** | Public API breaking change OR cross-plugin coupling OR config schema change |\n\nHigh-blast-radius proposals require explicit approval even\nunder `--auto-apply`. The skill warns when the radius rises\nabove the user's current `--auto-apply` ceiling.\n\n## Reversal plan template\n\n```\nReversal:\n  command: git revert <sha> --no-edit\n  retry condition: <when it would be safe to reapply>\n  evidence file: reviews/harden-<date>.md (this report)\n```\n\nFor config changes that cannot be reverted by `git revert`\nalone (e.g., a CI permission change that runs only on push):\n\n```\nReversal:\n  command: git revert <sha> --no-edit\n  follow-up: re-trigger the workflow on master to confirm the\n             permissions are restored\n  evidence file: reviews/harden-<date>.md\n```\n\n## Expected-passing test\n\nEach proposal cites a test that should pass after the change:\n\n- If a test already exists, name it: `tests/unit/x.py::test_y`.\n- If a test must be added, the proposal includes the test code in\n  the same diff block. The test must fail against the\n  pre-proposal code (RED) and pass after (GREEN).\n\nA proposal without an expected test is downgraded to ADVISORY.\nThis is the harden equivalent of `Skill(imbue:proof-of-work)`'s\nIron Law.\n\n## Approval options (per finding)\n\nWhen the approval gate fires, the user gets:\n\n1. **apply** — apply the diff, commit, run gates, advance.\n2. **file** — create a GitHub issue with the proposal body and\n   close out the finding.\n3. **defer** — log to `.harden/backlog.md` for future runs to\n   surface again.\n4. **reject** — record a rejection with optional rationale; the\n   finding will not surface again unless code changes invalidate\n   the rejection.\n\nThe auto-apply ceiling determines which severities skip the gate\nentirely:\n\n```bash\n/harden --auto-apply low      # apply LOW automatically\n/harden --auto-apply medium   # apply LOW + MEDIUM automatically\n/harden --auto-apply high     # apply LOW + MEDIUM + HIGH automatically\n```\n\nCRITICAL is never auto-applied.\n\n## Worked example\n\n```yaml\nid: PY01\nseverity: HIGH\ncitation: \"CWE-502 (Deserialization of Untrusted Data), NIST SSDF PW.7\"\nfile: src/api/loader.py\nlines: 42-44\ndetection_signal: |\n  Module imports the Python stdlib unsafe-deserialization helper\n  and calls its loads() helper on bytes that originate from the\n  request body (data flows from request.body through validate()\n  into loader.loads()).\nproposal: |\n  Replace the unsafe loader call with json.loads. The payload\n  shape is JSON-compatible per the API spec (verified by reading\n  the OpenAPI schema for /v1/upload). This eliminates the\n  arbitrary-code-execution attack path while preserving the\n  positive-path behavior.\ndiff: |\n  --- a/src/api/loader.py\n  +++ b/src/api/loader.py\n  @@ -42,3 +42,5 @@\n  -from <stdlib-unsafe-loader> import loads\n  +import json\n  -    obj = loads(payload)\n  +    obj = json.loads(payload)\nblast_radius: low\nreversal_plan:\n  command: \"git revert <sha> --no-edit\"\n  retry_condition: \"do not retry; the previous form was unsafe by design\"\n  evidence_file: \"reviews/harden-2026-05-10.md\"\nexpected_test: tests/unit/api/test_loader.py::test_round_trip_json\n```\n\n## Multi-file proposals\n\nWhen a hardening fix needs touches across multiple files (e.g.,\nadding a `Tier` `Literal` requires updates in classifiers, the\nDORAMetrics dataclass, and the tests), split into sibling\nproposals (PY01a, PY01b, PY01c) with a shared `parent_id`. The\napproval gate applies them as one unit, but each is its own\ncommit so reverts stay surgical.\n\n## What a proposal must NOT do\n\n- Modify generated code, vendored code, or `node_modules`.\n- Touch the changelog except to add a `### Security` bullet.\n- Bump dependency versions beyond the minimum required for the\n  fix (a separate proposal per dep upgrade).\n- Introduce a new dependency without an `imbue:proof-of-work`\n  evidence trail showing the dep was vetted.\n- Disable existing tests or assertions to make the fix easier.\n\nFile v1.9.19:modules/python-checks.md\n\n# Python Hardening Checks\n\nDetectors for Python codebases. Each row is a discrete check the\nskill runs; each carries a CWE citation for the report.\n\nThe detection-signal column uses placeholder syntax for patterns\nthat the project's pre-commit security hooks block writing\nliterally. The hooks exist for a reason: this doc describes the\nrules, but the regexes themselves live in code where the safety\nreview treats them as data, not source. If a future contributor\nneeds to inspect the literal patterns, see the corresponding\ndetector module under `plugins/pensive/skills/harden/detectors/`\n(future work; not part of the v1 skill).\n\n## Detection ruleset\n\n| ID | Check | CWE | NIST SSDF | Detection signal |\n|----|-------|-----|-----------|------------------|\n| PY01 | Unsafe deserialization (the stdlib `pickle` family, `marshal`, `shelve`) | CWE-502 | PW.5.1 | `<unsafe-loader>.loads(` on bytes you do not control |\n| PY02 | YAML loaded without a safe Loader | CWE-502 | PW.9 | `yaml.load(` without `Loader=SafeLoader` |\n| PY03 | Code injection via `eval`/`exec`/`compile(...,'exec')` | CWE-94 | PW.5.1 | `<eval-family>(` with a non-constant argument |\n| PY04 | Shell-command injection in a child-process call | CWE-78 | PW.5.1 | bandit B602 / B605: child-process helper invoked with the shell-mode flag and a formatted string |\n| PY05 | SQL injection via string formatting | CWE-89 | PW.5.1 | `cursor.execute(f\"...\")` or `% ` formatting in a query |\n| PY06 | Path traversal in user-supplied paths | CWE-22 | PW.5.1 | `open(user_input)` without `Path.resolve()` and `is_relative_to()` |\n| PY07 | Insecure RNG used for security purposes | CWE-330 | PW.5.1 | `import random` then a token/secret/key generated from it; should be `secrets` |\n| PY08 | TLS verification disabled | CWE-295 | PW.9 | `requests.*(verify=False)`, `ssl.CERT_NONE`, `disable_warnings(InsecureRequestWarning)` |\n| PY09 | Hardcoded credentials | CWE-798 | PW.5.1 | regex match for `api[_-]?key`, `secret`, `token`, `passwd` literals; AWS prefixes (`AKIA...`) |\n| PY10 | Subprocess invocation without timeout | CWE-400 | PW.5.1 | `<child-proc>.run/Popen` without `timeout=` |\n| PY11 | Tarfile extraction without member filter | CWE-22 | PW.9 | `tarfile.*extractall(` without `filter=` (PEP 706; default became safe in 3.12+) |\n| PY12 | XML XXE / billion-laughs | CWE-611, CWE-776 | PW.9 | `xml.etree.ElementTree.parse(` (use `defusedxml`) |\n| PY13 | Jinja autoescape off in HTML context | CWE-79 | PW.9 | `Environment(autoescape=False)` or `Markup(user_input)` |\n| PY14 | Logging secrets | CWE-532 | PW.5.1 | `logger.*(token)`, `logger.*(password)`, `logger.*(api_key)` |\n| PY15 | Bare `except:` swallowing errors in security paths | CWE-754 | PW.7 | `except:` or `except Exception: pass` in auth or crypto paths |\n| PY16 | Async TOCTOU (time-of-check / time-of-use) | CWE-367 | PW.5.1 | `await is_authorized(...)` then `await act(...)` without re-check |\n| PY17 | Untrusted format string | CWE-134 | PW.5.1 | `(user_input).format(`, f-string built from user input, `\"%\" % user` |\n| PY18 | Insecure temp file | CWE-377 | PW.5.1 | `tempfile.mktemp(` (use `mkstemp` or `NamedTemporaryFile`) |\n| PY19 | `assert` for runtime auth check | CWE-617 | PW.5.1 | `assert user.is_admin` (assert is stripped under `python -O`) |\n| PY20 | `requests` without timeout | CWE-400 | PW.5.1 | `requests.get/post(...)` without `timeout=` |\n| PY21 | HTTP request smuggling on outdated frameworks | CWE-444 | RV.1 | `gunicorn<22.0.0` (CVE-2024-1135), `aiohttp<3.9.2` (CVE-2024-23829) |\n| PY22 | Multipart resource exhaustion | CWE-400 | RV.1 | `python-multipart<0.0.18` (CVE-2024-47874); FastAPI route without `max_part_size` |\n| PY23 | Weak hashing for passwords or auth tokens | CWE-327, CWE-328 | PW.5.1 | `hashlib.md5`, `hashlib.sha1` reachable from password / session-token paths |\n| PY24 | Missing TLS 1.2 floor | CWE-326 | PW.9 | `ssl.PROTOCOL_TLSv1`, `PROTOCOL_SSLv23` without `minimum_version` |\n| PY25 | Index pinning missing for PyPI consumption | CWE-829 | PW.4 | no `[[tool.uv.index]]` in `pyproject.toml`; no `--index-url` constraint in `requirements.txt` |\n| PY26 | Hash-unpinned installs | CWE-494, NIST SI-7 | PW.4 | `requirements.txt` without `--hash=` lines; missing `uv.lock`/`poetry.lock` |\n| PY27 | PyPI release without PEP 740 attestation | NIST SSDF PS.2.1 | PS.2 | release workflow uses static API token instead of `pypa/gh-action-pypi-publish@release/v1` (Trusted Publishers) |\n\n## Library substitution table\n\nWhen a finding fires, the proposal usually swaps the offending\nlibrary or call. The substitution table:\n\n| Bad | Good | Why |\n|-----|------|-----|\n| the unsafe-deserialization stdlib family | `json` if data is JSON-shaped, otherwise `msgspec` / `pydantic` | safe-by-default deserialization |\n| `yaml.load(...)` | `yaml.safe_load(...)` (or `ruamel.yaml.YAML(typ='safe')`) | rejects arbitrary tag construction |\n| `eval`, `exec` | `ast.literal_eval` for constants; otherwise refactor to a typed parser | no code path executes user input |\n| `random.{choice,token_bytes,...}` for security | `secrets.token_bytes/urlsafe`, `secrets.choice` | CSPRNG-backed |\n| `xml.etree.ElementTree` on untrusted input | `defusedxml.ElementTree` | XXE / billion-laughs hardened |\n| `urllib.request.urlopen` | `requests` (`timeout=`, `verify=True`) or `httpx` (defaults are safer) | timeout-by-default |\n| `tempfile.mktemp` | `tempfile.NamedTemporaryFile(delete=False)` | atomic creation |\n| `assert is_authorized()` | explicit `if not is_authorized(): raise PermissionError(...)` | survives `python -O` |\n| `hashlib.md5/sha1` for passwords | `argon2-cffi`, `bcrypt`, or `passlib` | KDF with cost factor |\n| static API tokens for PyPI | PyPI Trusted Publishers and sigstore attestation (PEP 740) | revocable, log-traceable, no shared secret |\n\n## Static-analyzer integration\n\nRun the canonical Python security tools and treat their findings\nas first-class harden findings:\n\n```bash\n# Bandit ruleset (PyCQA-maintained AST scanner)\nuv run bandit -r src/ -f json -o /tmp/harden-bandit.json\n\n# pip-audit on the lockfile (PyPA + Trail of Bits, OSV-backed)\nuv run pip-audit --lockfile uv.lock --format json > /tmp/harden-pipaudit.json\n\n# osv-scanner reads pyproject + lockfiles + Cargo.lock\nosv-scanner --format json . > /tmp/harden-osv.json\n\n# semgrep with the security-audit ruleset\nsemgrep --config=p/python --json --output=/tmp/harden-semgrep.json\n```\n\nFindings from these tools convert to the harden schema by joining\non file:line and severity. A bandit B301 finding (the unsafe\ndeserialization rule) becomes the same finding shape as the\ninternal PY01 detector, so the report does not double-count.\n\n## Frontier Python concerns (2025-2026)\n\nLoaded from `frontier-checks.md` for full coverage. Brief list:\n\n- PEP 740 sigstore attestations on PyPI (verify before install);\n  see Trail of Bits' \"Attestations: a new generation of\n  signatures on PyPI\" (Nov 2024).\n- Tarfile member filter (PEP 706) — `tarfile.data_filter` default\n  in Python 3.12+; verify the codebase does not still pass\n  `filter=None`.\n- pyproject.toml `[[tool.uv.index]]` priority pinning to defeat\n  dependency confusion attacks.\n- LLM SDK prompt-injection patterns and MCP server hardening\n  (CWE-1426; OWASP LLM Top 10 #01, #02).\n- ASGI middleware request smuggling (CVE-2024-23829 class).\n- Sandboxing application code: WASM (Pyodide), gVisor, nsjail.\n- Slopsquatting / package hallucination (arXiv 2406.10279):\n  LLM-suggested non-existent packages later registered as\n  malware. Mitigation: lockfile and `--require-hashes` and human\n  review on every dep addition.\n\n## Output schema\n\nEach Python finding follows the schema in\n`modules/proposal-shape.md`. The detection-signal text uses safe\nplaceholders so the doc itself does not trip secret-scanners or\nthe project's security pre-commit hooks; the actual scanner emits\nthe literal pattern with file:line context in the report.\n\nFile v1.9.19:modules/rust-checks.md\n\n# Rust Hardening Checks\n\nDetectors for Rust codebases. The Rust ecosystem ships strong\ndefault safety; the harden skill verifies the discipline is\nactually applied and the supply chain is curated.\n\nFor a deep ownership/unsafe audit, the skill defers to\n`Skill(pensive:rust-review)`. This module focuses on the\nhardening posture (capability use, supply-chain hygiene,\nside-channel defense) and frontier 2025-2026 practices.\n\n## Detection ruleset\n\n| ID | Check | CWE / RustSec | NIST SSDF | Detection signal |\n|----|-------|---------------|-----------|------------------|\n| RS01 | Crate root lacks `#![forbid(unsafe_code)]` and does not declare audited unsafe | CWE-119 | PW.5 | `lib.rs`/`main.rs` without forbid; no `audit/unsafe.md` |\n| RS02 | Unsafe block without `// SAFETY:` comment | CWE-119 | PW.7 | `unsafe {` not preceded by `// SAFETY:` line |\n| RS03 | `unwrap()` / `expect()` on caller-supplied data | CWE-754 | PW.5 | `.unwrap()` after `parse()`, `from_str`, `serde::from_*` on external input |\n| RS04 | `panic!` reachable from request handler | CWE-754 | PW.5 | `panic!`, `unimplemented!`, `unreachable!` on user-input branches |\n| RS05 | `cargo audit` not wired to CI | RV.1 | RV.1 | no `cargo audit` step in `.github/workflows/*.yml` |\n| RS06 | `cargo deny` config missing or not enforced | RV.1 | PW.4 | no `deny.toml` or CI step missing |\n| RS07 | `cargo vet` audits stale / missing for new deps | RV.2 | PW.4 | `supply-chain/audits.toml` does not cover new entries in `Cargo.lock` |\n| RS08 | Comparing secrets with `==` | CWE-208 | PW.5 | `==` between `&[u8]` typed as token/secret/digest; should be `subtle::ConstantTimeEq` |\n| RS09 | Secrets not zeroized on drop | CWE-316 | PW.5 | secret-typed struct without `Zeroize`/`ZeroizeOnDrop` |\n| RS10 | Async cancellation un-safe | CWE-362 | PW.5 | `tokio::select!` arms with non-cancel-safe futures (e.g., `BufReader::read_to_end`) |\n| RS11 | `Mutex::lock().unwrap()` in hot path | CWE-754 | PW.5 | poisoned-lock unwrap reachable from public API |\n| RS12 | Source replacement to private registry without integrity pin | CWE-494 | PW.4 | `[source.crates-io]` `replace-with` without checksum |\n| RS13 | Git dependency without `rev=` | CWE-494 | PW.4 | `git = \"...\"` without `rev = \"...\"` (mutable target) |\n| RS14 | Build script (`build.rs`) reads files outside `OUT_DIR` | CWE-829 | PW.6 | `build.rs` opens path containing `..` |\n| RS15 | `serde(deny_unknown_fields)` missing on auth-bearing structs | CWE-1287 | PW.5 | struct deriving `Deserialize` for an auth/config payload without `#[serde(deny_unknown_fields)]` |\n| RS16 | Compiler hardening flags absent | CWE-1244 | PW.6 | `.cargo/config.toml` missing `RUSTFLAGS` for stack protection / CFI |\n| RS17 | `unsafe impl Send/Sync` without proof | CWE-362 | PW.7 | `unsafe impl (Send|Sync) for ...` without SAFETY comment |\n| RS18 | FFI without bounds annotation | CWE-787 | PW.5 | `extern \"C\"` function with `*const T` / `*mut T` arg with no length param |\n\n## Tooling integration\n\n```bash\n# Vulnerability scan against RustSec advisory DB\ncargo audit --json > /tmp/harden-cargo-audit.json\n\n# Policy enforcement (license, advisory, source, ban list)\ncargo deny check --format json 2>/tmp/harden-deny.json\n\n# Cryptographic-supply-chain audit\ncargo vet check 2>&1 | tee /tmp/harden-vet.log\n\n# Unsafe block inventory (third-party tool; requires install)\ncargo geiger --output-format json > /tmp/harden-geiger.json\n\n# Mutation testing (high-leverage; expensive)\ncargo mutants --in-diff origin/main..HEAD --no-times --json\n```\n\nThe harden report joins these on file:line and advisory ID.\n\n## Capability-style hardening (frontier 2025-2026)\n\n| From | To | Why |\n|------|-----|-----|\n| `std::fs` ambient access | `cap-std::fs::Dir` capability | filesystem ops require an explicit handle, not a path |\n| raw `socket`/`std::net` | `cap-std::net` | network endpoints are capabilities, not strings |\n| environment-driven config | `secrecy::SecretString` for secrets | wrapper prevents `Debug`/`Display` leaks |\n| ad-hoc retry loops | `tower::retry` with backoff and budget | bounded resource consumption (CWE-400) |\n\nThese are recommendations, not blocking findings — surface in\nthe report as MEDIUM advisories with the rationale in the\nproposal.\n\n## Concurrency hardening\n\n| Pattern | Replace with | Reason |\n|---------|--------------|--------|\n| naked `std::sync::Mutex` in hot path | `parking_lot::Mutex` (no poisoning, smaller, faster) | reduces unwrap-on-poison footguns |\n| ad-hoc `Arc<Mutex<HashMap>>` | `dashmap::DashMap` | lock-free reads, sharded writes |\n| `tokio::sync::Mutex` held across `await` | `parking_lot::Mutex` for short critical sections | avoid tokio scheduler stalls |\n| `loom`-untested concurrent code | wire `cargo test --features loom` for lock-free types | model-checks all interleavings |\n\n## Compiler hardening flags\n\nIn `.cargo/config.toml`:\n\n```toml\n[target.'cfg(all())']\nrustflags = [\n    # Stack-smashing protection\n    \"-C\", \"force-frame-pointers=yes\",\n    # Disable sources of UB\n    \"-D\", \"warnings\",\n    # Treat unsafe-op-without-unsafe-fn as error in 2024 edition\n    \"-D\", \"unsafe_op_in_unsafe_fn\",\n]\n```\n\nFor sanitizer-instrumented test runs:\n\n```bash\nRUSTFLAGS=\"-Z sanitizer=address\" cargo +nightly test --target x86_64-unknown-linux-gnu\n```\n\n## Output schema\n\nSame as `python-checks.md`. Each Rust finding emits a single\nproposal with diff, blast radius, reversal plan, and expected\ntest. RustSec IDs go in the citation column when applicable.\n\nFile v1.9.19:skill-card.md\n\n## Description:\n\nApplies NIST/CWE security hardening to Python and Rust code.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[athola](https://clawhub.ai/user/athola)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and engineers use this skill to audit repositories for Python, Rust, dependency, CI/CD, container, secret-handling, and frontier security issues. It produces citation-backed findings and concrete remediation proposals that can be approved, deferred, filed, or rejected.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can post security audit summaries to pull requests without an explicit publication approval step.\n\nMitigation: Require manual review before any security summary is posted, especially for public repositories or private repositories with broad pull request access.\n\nRisk: Repository-wide security auditing can lead to code, configuration, or report changes under user-approved workflows.\n\nMitigation: Run the first invocation in report-only mode, approve proposals one at a time, apply one finding per commit, and re-run project gates after each approved change.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/athola/skills/nm-pensive-harden)\n- [Project homepage](https://github.com/athola/claude-night-market/tree/master/plugins/pensive)\n- [NIST and CWE citation backbone](artifact/modules/nist-controls.md)\n- [Proposal shape](artifact/modules/proposal-shape.md)\n\n## Skill Output:\n\n**Output Type(s):** [Analysis, Markdown, Code, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown reports with findings tables, remediation proposals, shell command blocks, and code or configuration diffs.]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Findings include severity, citation, disposition, blast-radius, reversal plan, and expected test; approved changes may be applied as discrete commits.]\n\n## Skill Version(s):\n\n1.9.19 (source: server release evidence; artifact frontmatter says 1.9.8)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.9.17: 9 files, 23205 bytes\n\nFiles: modules/cross-cutting.md (5415b), modules/frontier-checks.md (5056b), modules/nist-controls.md (4262b), modules/proposal-shape.md (5761b), modules/python-checks.md (7917b), modules/rust-checks.md (5491b), skill-card.md (2228b), SKILL.md (10269b), _meta.json (137b)\n\nFile v1.9.17:SKILL.md\n\n---\nname: harden\ndescription: Applies NIST/CWE security hardening to Python and Rust code\nversion: 1.9.8\ntriggers:\n  - security\n  - hardening\n  - nist\n  - supply-chain\n  - python\n  - rust\n  - cwe\n  - auditing code for vulnerabilities or proposing concrete security remediations\nmetadata: {\"openclaw\": {\"homepage\": \"https://github.com/athola/claude-night-market/tree/master/plugins/pensive\", \"emoji\": \"\\ud83d\\udd12\", \"requires\": {\"config\": [\"night-market.pensive:safety-critical-patterns\", \"night-market.pensive:rust-review\", \"night-market.pensive:bug-review\", \"night-market.pensive:tiered-audit\", \"night-market.pensive:blast-radius\", \"night-market.leyline:supply-chain-advisory\", \"night-market.leyline:authentication-patterns\", \"night-market.leyline:content-sanitization\", \"night-market.abstract:hook-authoring\", \"night-market.imbue:proof-of-work\"]}}}\nsource: claude-night-market\nsource_plugin: pensive\n---\n\n> **Night Market Skill** — ported from [claude-night-market/pensive](https://github.com/athola/claude-night-market/tree/master/plugins/pensive). For the full experience with agents, hooks, and commands, install the Claude Code plugin.\n\n\n# Harden Codebase Skill\n\nActive security hardening — scan the existing repository for\nvulnerabilities and forward-facing threats, then propose concrete\nremediations the user can approve, defer, or file.\n\nThis skill is the engine behind `/harden`. It complements the\nClaude Code built-in `/security-review` (which scans the pending\ndiff) by sweeping the whole repository against citation-backed\nchecks rather than line-level review of in-flight code.\n\n## When To Use\n\n- Quarterly security-posture audits.\n- Before tagging a release that touches sensitive code paths.\n- After a published advisory affects the language ecosystem.\n- When onboarding a new repository and want a baseline.\n- After integrating a new dependency or upstream service.\n\n## When NOT To Use\n\n- Pending-diff review on a single PR. Use `/security-review`.\n- Architecture-level threat modeling. Use `attune:war-room`\n  with a security-focused panel.\n- Cryptographic protocol review. The skill flags suspect crypto\n  but does not propose protocol fixes (specialist work).\n- One-off bug hunting. Use `pensive:bug-review`.\n\n## Required TodoWrite Items\n\n1. `harden:discovery` — inventory languages, build files, hooks,\n   CI workflows\n2. `harden:scan-python` — run python-checks.md detectors when\n   Python is present\n3. `harden:scan-rust` — run rust-checks.md detectors when Rust\n   is present\n4. `harden:scan-cross-cutting` — run cross-cutting.md detectors\n   (deps, secrets, SBOM, CI)\n5. `harden:scan-frontier` — run frontier-checks.md (PQC, LLM\n   supply chain, sandboxing)\n6. `harden:nist-mapping` — map findings to NIST SSDF practices\n7. `harden:proposals` — for each finding above the threshold,\n   draft a concrete remediation per `modules/proposal-shape.md`\n8. `harden:approval-gate` — present proposals to the user for\n   apply / file / defer / reject\n9. `harden:apply-and-validate` — apply approved proposals as\n   discrete commits, re-run gates, capture evidence\n10. `harden:report` — write `reviews/harden-<date>.md` and\n    optionally post to Discussions\n\n## Progressive Loading\n\nLoad modules based on what the discovery step finds.\n\n| Detected | Load |\n|----------|------|\n| Python files (`*.py`, `pyproject.toml`) | `modules/python-checks.md` |\n| Rust files (`*.rs`, `Cargo.toml`) | `modules/rust-checks.md` |\n| Any | `modules/nist-controls.md` (citation backbone) |\n| Any | `modules/cross-cutting.md` (deps, secrets, CI) |\n| LLM SDK use (`anthropic`, `openai`), MCP server, post-quantum surface | `modules/frontier-checks.md` |\n| Any with proposals enabled | `modules/proposal-shape.md` |\n\nThe module hub keeps the SKILL.md itself under the\n`estimated_tokens: 1100` budget. Detail lives in the modules.\n\n## Core Workflow\n\n### Phase 1 — Discovery\n\nInventory the repo without modifying anything:\n\n```bash\n# Languages and build files\nfind . -type f \\( -name '*.py' -o -name '*.rs' -o -name '*.sh' \\) \\\n  | head -200 > /tmp/harden-langs.txt\n\n# Build manifests\nls pyproject.toml Cargo.toml package.json go.mod 2>/dev/null\n\n# CI workflows and pre-commit\nls .github/workflows/ .pre-commit-config.yaml 2>/dev/null\n\n# Hooks and Dockerfiles\nfind . -path ./node_modules -prune -o -type f \\\n  \\( -name 'hooks.json' -o -name 'Dockerfile*' \\) -print\n```\n\nDispatch `/discovery-prefilter` if the repo has > 5000 source files\nto bound the scan.\n\n### Phase 2 — Citation-backed scan\n\nFor each detected language, load the matching module and run its\ndetector list. Each detector outputs findings with the schema\ndefined in `modules/proposal-shape.md`. The citation column is\nmandatory: a finding without a NIST/CWE reference is downgraded\nto \"advisory\" and not eligible for active proposal.\n\n### Phase 3 — NIST mapping\n\nGroup findings by SSDF practice (PW.4, PW.8, RV.1, etc.) and CWE\nID. The mapping table lives in `modules/nist-controls.md`. The\nreport's executive summary references SSDF practice coverage so\nthe audit is comparable across runs.\n\n### Phase 4 — Proposal generation\n\nFor each finding above the configured severity threshold, draft a\nconcrete remediation per `modules/proposal-shape.md`:\n\n- Specific files and lines touched\n- Diff or config snippet (not \"consider doing X\")\n- Blast-radius assessment via `pensive:blast-radius`\n- Reversal plan: how to revert if the change breaks behavior\n- Test that should pass after the change\n\n### Phase 5 — Approval gate\n\nPresent proposals one at a time via `AskUserQuestion`. Default\noptions: **apply**, **file as issue**, **defer to backlog**,\n**reject**. Auto-apply is opt-in via the `--auto-apply` flag and\nrespects a per-finding severity threshold.\n\n### Phase 6 — Apply and validate\n\nApply each approved proposal as a discrete commit:\n\n```bash\ngit add <touched files>\ngit commit -m \"harden: <finding-id> <one-line summary>\"\n```\n\nAfter each apply, re-run the project gates:\n\n```bash\nmake test --quiet && make lint && make type-check\n```\n\nIf a gate fails, revert the commit (`git revert HEAD --no-edit`)\nand downgrade the finding to \"needs human design.\"\n\n### Phase 7 — Report\n\nWrite `reviews/harden-<date>.md` with:\n\n- Executive summary (SSDF practice coverage, CWE distribution)\n- Findings table grouped by severity\n- Per-finding detail: detection signal, citation, proposal, status\n- Disposition table (applied / filed / deferred / rejected)\n- Re-run instructions\n\nIf running inside a PR context, post the executive summary as a\ncomment via `abstract:post_review_insights`.\n\n## Severity Classification\n\n| Severity | Definition | Default disposition |\n|----------|------------|---------------------|\n| **CRITICAL** | Active exploit path, RCE, credential leak | apply or file immediately |\n| **HIGH** | Plausible exploit, missing defense-in-depth on attack surface | propose for apply |\n| **MEDIUM** | Best-practice gap, hardening opportunity | propose for apply with `--auto-apply medium` |\n| **LOW** | Style/documentation gap with security flavor | file as issue |\n| **ADVISORY** | Pattern detected without exploit narrative | report only |\n\n## Output Format\n\n```markdown\n# Hardening Report — <date>\n\n## Executive Summary\n\n- Codebase: <repo> @ <sha>\n- Languages scanned: Python (X files), Rust (Y files)\n- NIST SSDF practices covered: PW.4, PW.7, PW.8, RV.1, RV.2\n- CWE Top 25 hits: <count> across <distinct CWEs>\n- Disposition: <N> applied, <N> filed, <N> deferred, <N> rejected\n\n## Findings\n\n| ID | Severity | Citation | File:Line | Disposition |\n|----|----------|----------|-----------|-------------|\n| H1 | CRITICAL | CWE-502, NIST SSDF PW.7 | `src/x.py:45` | applied (commit abc123) |\n| H2 | HIGH | CWE-89, NIST SSDF PW.4 | `src/y.py:120` | filed (#456) |\n\n## Per-finding detail\n\n### H1 — Unsafe deserialization\n\n**Citation:** CWE-502 (Deserialization of Untrusted Data),\nNIST SSDF PW.7 (Review and analyze human-readable code).\n\n**Detection signal:**\n- File: `src/x.py:45`\n- Pattern: <module>.loads(user_supplied_input)\n- Reachability: untrusted, comes from request body\n\n**Proposal:** ...\n\n**Blast radius:** ...\n\n**Reversal plan:** ...\n```\n\n## Safety Rails\n\n- **Never apply without approval.** Even with `--auto-apply`,\n  CRITICAL findings always prompt.\n- **One finding per commit.** Reversals are per-finding, not\n  per-batch.\n- **Re-run gates after each apply.** A gate failure reverts the\n  commit and downgrades the finding.\n- **Citation is mandatory.** Findings without a NIST/CWE/RustSec\n  reference are advisory only and skip the apply phase.\n- **Read-only on first run.** First invocation defaults to\n  `--report-only` until the user has reviewed at least one\n  report and explicitly opts into proposals.\n\n## Integration\n\nThe skill composes (rather than re-implements):\n\n- `pensive:rust-review` — full Rust audit when Rust is present\n- `pensive:bug-review` — bug-hunting backbone\n- `pensive:safety-critical-patterns` — NASA Power-of-10 adapted\n- `pensive:tiered-audit` — three-tier discipline (`--tier 1/2/3`)\n- `pensive:blast-radius` — change-impact assessment for proposals\n- `leyline:supply-chain-advisory` — dependency posture\n- `leyline:authentication-patterns` — auth/credential review\n- `leyline:content-sanitization` — input handling\n- `abstract:hook-authoring` — hook-event security\n- `imbue:proof-of-work` — evidence discipline for findings\n\n## Exit Criteria\n\n- [ ] Discovery output lists every language and build manifest\n      detected in the repo.\n- [ ] Each finding carries a CWE or NIST SSDF citation; the\n      report executive summary lists the SSDF practice coverage.\n- [ ] Each finding above the severity threshold has a concrete\n      proposal (file, diff or config snippet, blast radius,\n      reversal plan, expected-passing test).\n- [ ] No proposal was applied without explicit user approval\n      (or without an `--auto-apply` flag covering its severity).\n- [ ] Each applied proposal is its own commit, reversal-friendly.\n- [ ] After every apply, the project gates were re-run; any\n      gate failure reverted the commit and downgraded the\n      finding.\n- [ ] `reviews/harden-<date>.md` exists and lists every finding\n      with a disposition (applied / filed / deferred / rejected /\n      advisory).\n\nFile v1.9.17:_meta.json\n\n{\n  \"ownerId\": \"kn7d107jg9jv602h9ytsegydq184a42s\",\n  \"slug\": \"nm-pensive-harden\",\n  \"version\": \"1.9.17\",\n  \"publishedAt\": 1785389940969\n}\n\nFile v1.9.17:modules/cross-cutting.md\n\n# Cross-Cutting Hardening Checks\n\nChecks that apply regardless of the source language: dependency\nposture, secret hygiene, CI/CD chain, container shape, and the\nSBOM.\n\n## Dependency posture (composes leyline:supply-chain-advisory)\n\n| ID | Check | CWE / NIST | Detection |\n|----|-------|------------|-----------|\n| DEP01 | Lockfile committed | PW.4 | absence of `uv.lock` / `Cargo.lock` / `package-lock.json` |\n| DEP02 | Dependency scanner runs in CI | RV.1 | no `pip-audit`/`cargo audit`/`npm audit` step in workflows |\n| DEP03 | Known-bad versions blocked | CWE-829 | `leyline:supply-chain-advisory` blocklist not consulted |\n| DEP04 | Auto-update bot configured | RV.1 | no `dependabot.yml` / `renovate.json` |\n| DEP05 | Direct deps pinned to exact versions | CWE-494 | `^1.2` / `~1.2` / `1.2.*` for security-critical deps |\n| DEP06 | Hash-pinned for top-tier supply-chain trust | CWE-494 | `--require-hashes` not used in `pip` / `requirements.txt` |\n| DEP07 | License policy enforced | none | no `cargo deny` license rules / no `pip-licenses` check |\n\n## Secret hygiene\n\n| ID | Check | CWE | Detection |\n|----|-------|-----|-----------|\n| SEC01 | Pre-commit secret scanner installed | CWE-798 | no `gitleaks` / `trufflehog` / `talisman` in `.pre-commit-config.yaml` |\n| SEC02 | `.env` files git-ignored | CWE-200 | `.env` tracked or unmatched in `.gitignore` |\n| SEC03 | Long-lived secrets in CI | CWE-798 | `secrets.SOME_KEY` used without `if: github.event_name != 'pull_request'` |\n| SEC04 | OIDC publishing configured | CWE-798 | PyPI/Cargo publish step uses `password:` rather than OIDC `id-token: write` |\n| SEC05 | Audit trail for secret access | PW.7 | repo settings: secret-access logs not retained |\n| SEC06 | Sealed-secrets / secret manager | CWE-798 | secrets baked into config files instead of fetched from a manager |\n\n## CI/CD chain (GitHub Actions example)\n\n| ID | Check | NIST SSDF | Detection |\n|----|-------|-----------|-----------|\n| CI01 | Third-party actions pinned by SHA, not tag | PW.4 | `uses: foo/bar@v1` instead of `@<full SHA>` |\n| CI02 | `permissions:` block per workflow | PW.4 | top-level `permissions:` missing or `permissions: write-all` |\n| CI03 | `GITHUB_TOKEN` minimum scope | PW.4 | default permissions used when `contents: read` would suffice |\n| CI04 | Concurrency cancel for stale runs | RV.2 | no `concurrency.cancel-in-progress: true` |\n| CI05 | Workflow dispatch requires approval for protected branches | PW.4 | branch protection allows direct dispatch |\n| CI06 | SLSA provenance generated for releases | RV.2 | release workflow does not invoke `slsa-framework/slsa-github-generator` |\n| CI07 | SBOM generated and attached to releases | RV.2 | release workflow lacks `cyclonedx`/`syft`/`spdx-sbom-generator` step |\n\n## Container hardening (when Dockerfiles exist)\n\n| ID | Check | CWE | Detection |\n|----|-------|-----|-----------|\n| CO01 | Non-root `USER` set | CWE-269 | `USER root` or `USER` directive missing |\n| CO02 | `FROM` is digest-pinned | CWE-494 | `FROM ubuntu:22.04` instead of `FROM ubuntu@sha256:...` |\n| CO03 | Distroless or slim base for production | PW.4 | `FROM ubuntu:latest` / `FROM debian:latest` for runtime image |\n| CO04 | Read-only root filesystem in compose | CWE-269 | `read_only: true` not set |\n| CO05 | seccomp/apparmor profile referenced | CWE-269 | runtime config lacks profile |\n| CO06 | Multi-stage build to drop build deps | CWE-665 | single-stage `FROM` keeps `gcc`, `make`, etc. in runtime |\n| CO07 | `HEALTHCHECK` defined | none | no liveness signal (operational hygiene) |\n\n## SBOM and provenance\n\n```bash\n# CycloneDX SBOM for the whole repo\nsyft . -o cyclonedx-json > sbom.cdx.json\n\n# SPDX SBOM (alternative format)\nsyft . -o spdx-json > sbom.spdx.json\n\n# Verify against the in-toto attestation if released\ncosign verify-attestation --type slsaprovenance \\\n  --certificate-identity-regexp '.*' --certificate-oidc-issuer-regexp '.*' \\\n  ghcr.io/<org>/<image>:<tag>\n```\n\nThe hardening report includes an SBOM-coverage row: present /\nabsent for each release artifact in the repo.\n\n## Pre-commit security suite\n\nThe skill proposes adding (or extending) `.pre-commit-config.yaml`\nwith:\n\n```yaml\nrepos:\n  - repo: https://github.com/PyCQA/bandit\n    rev: 1.7.10\n    hooks:\n      - id: bandit\n        args: [\"-c\", \"pyproject.toml\"]\n        additional_dependencies: [\"bandit[toml]\"]\n  - repo: https://github.com/gitleaks/gitleaks\n    rev: v8.21.2\n    hooks:\n      - id: gitleaks\n  - repo: https://github.com/Yelp/detect-secrets\n    rev: v1.5.0\n    hooks:\n      - id: detect-secrets\n        args: [\"--baseline\", \".secrets.baseline\"]\n```\n\nIf `cargo` is on PATH:\n\n```yaml\n  - repo: local\n    hooks:\n      - id: cargo-deny\n        name: cargo deny\n        entry: cargo deny check\n        language: system\n        files: 'Cargo\\.(toml|lock)$'\n```\n\n## Severity defaults\n\n| Family | Default | Justification |\n|--------|---------|---------------|\n| DEP04, DEP07, CI07, CO07 | LOW | operational hygiene; no exploit narrative |\n| DEP01, DEP02, SEC01, SEC02, CI02, CI03, CO01, CO02 | MEDIUM | one defense-in-depth layer missing |\n| DEP03, SEC03, SEC04, CI01, CI06, CO03 | HIGH | exploitable supply-chain or privilege issue |\n| SEC03 with leaked active credential | CRITICAL | active exploit path |\n\nA finding can be promoted from default with evidence (e.g.,\nDEP01 promoted to HIGH if the lockfile is missing AND auto-merge\nis enabled on dep PRs).\n\nFile v1.9.17:modules/frontier-checks.md\n\n# Frontier Hardening Checks (2025-2026)\n\nForward-facing checks that defend against threats just emerging\nin production. Findings here are usually MEDIUM by default\nbecause exploitation is non-trivial; promote to HIGH when the\ncodebase has a high-value attack surface (auth provider, signing\nservice, data plane).\n\n## Post-quantum migration readiness\n\nThe NSA CNSA 2.0 timeline targets quantum-resistant crypto for\nNSS by 2030; PCI DSS 4.0.1 expects an inventory by 2026. Most\napplication code is not the right place to swap algorithms, but\nthe *crypto-agility* posture is.\n\n| ID | Check | Citation | Detection |\n|----|-------|----------|-----------|\n| PQ01 | Signing/verification has a single hard-coded algorithm | NIST IR 8547 | `algorithms = [\"RS256\"]` or `algorithms = [\"EdDSA\"]` literal in JWT/JWS code |\n| PQ02 | Algorithm selection driven by config, not code | NIST IR 8547 | move the algorithm list behind a `signing_algorithms` config field |\n| PQ03 | Inventory of crypto APIs in the repo | NIST CNSA 2.0 | no `docs/crypto-inventory.md` or equivalent |\n| PQ04 | TLS clients accept algorithm downgrade silently | CWE-757 | `requests` / `reqwest` defaults without minimum-TLS pin |\n\nThe proposal for PQ02 is usually a small refactor: move\n`algorithms = [\"EdDSA\"]` into a config table the operator can\noverride. The skill does not propose ML-DSA / Falcon migration\nin application code (still specialist work).\n\n## LLM and agentic supply chain\n\nA new failure mode in 2025: AI assistants suggest dependencies\nthat look plausible but do not exist (or are typosquats). The\nchecks below defend the development pipeline itself.\n\n| ID | Check | Citation | Detection |\n|----|-------|----------|-----------|\n| LLM01 | Index pinning to defeat dependency confusion | OWASP LLM Top 10 #08 | `pyproject.toml` lacks `[[tool.uv.index]]` priority order |\n| LLM02 | New deps require human review | OWASP LLM Top 10 #08 | no CI rule blocking auto-merge on dep PRs |\n| LLM03 | LLM SDK calls validate role/instruction boundaries | OWASP LLM Top 10 #01 | system prompt concatenated with user input without separator/role |\n| LLM04 | Tool-use response sanitization | OWASP LLM Top 10 #02 | tool output rendered to UI/terminal without escape |\n| LLM05 | MCP server allowlist of tools | OWASP LLM Top 10 #02 | MCP config mounts every tool from a server (no allowlist) |\n| LLM06 | Agent action audit trail | OWASP LLM Top 10 #06 | no log of tool invocations with inputs |\n\n## Sandbox / isolation posture\n\nFor codebases that execute user-supplied or AI-supplied code:\n\n| ID | Check | Why | Today's option |\n|----|-------|-----|----------------|\n| SB01 | User code runs in same process as host | host privilege escalation | Pyodide WASM (Python), wasmtime (Rust) |\n| SB02 | Network egress unrestricted from sandbox | data exfiltration | gVisor egress policy, NetworkPolicy in K8s |\n| SB03 | Filesystem capabilities ambient | path-based attacks | `cap-std` (Rust), bind-mount only required dirs |\n| SB04 | Resource limits absent | DoS via runaway workload | cgroup `memory.max`, `cpu.max`; `prlimit` in containers |\n\n## eBPF / runtime security hooks\n\nProduction codebases benefit from runtime monitoring even when\nthe static defenses are good. The skill flags absence:\n\n| ID | Check | Tool | What it catches |\n|----|-------|------|-----------------|\n| RT01 | Runtime detection layer present | Falco / Tetragon / Tracee | unexpected syscalls, container escapes |\n| RT02 | App emits structured audit events | OpenTelemetry traces with semantic conventions | post-incident reconstruction |\n| RT03 | Deployment includes seccomp/apparmor profile | runtime config | exploit blast-radius capping |\n\n## Differential-privacy / PETs awareness\n\nFor codebases that handle aggregable user data (analytics, ML\ntraining, telemetry):\n\n| ID | Check | Citation | Signal |\n|----|-------|----------|--------|\n| DP01 | Aggregations expose per-user values without noise | NIST SP 800-188 | counts/means published without DP budget |\n| DP02 | Logs retain raw PII beyond retention window | GDPR Art. 5 | log retention config absent or > 30 days for PII fields |\n\n## Memory-safety migration triage (when C/C++ is present)\n\nPer CISA's \"Secure by Design\" pledge and the ONCD memory-safety\nreport (Feb 2024), new code in safety-critical contexts should\nbe in a memory-safe language by default. The skill flags the\nopportunity, not the migration:\n\n| ID | Check | Signal | Proposal |\n|----|-------|--------|----------|\n| MS01 | C/C++ code paths handle untrusted input | parser, network code in C/C++ | rewrite or wrap behind a Rust shim |\n| MS02 | C-style string handling | `strcpy`, `sprintf`, `gets` | move to Rust or use `safestr`/`absl::Cord` |\n\n## Output\n\nFindings here use the same schema as the other modules. Severity\nis **MEDIUM** by default; promote to HIGH when:\n\n- The repo is an auth/signing/credentialing service (PQ findings)\n- The repo ships an MCP server or agent harness (LLM findings)\n- The repo has untrusted-code-exec posture (SB findings)\n- The repo handles regulated PII (DP findings)\n\nFile v1.9.17:modules/nist-controls.md\n\n# NIST and CWE Citation Backbone\n\nEvery finding in a hardening report carries a citation. This\nmodule is the lookup table.\n\n## NIST SSDF (SP 800-218) practice mapping\n\nThe Secure Software Development Framework defines four practice\ngroups: Prepare the Organization (PO), Protect Software (PS),\nProduce Well-Secured Software (PW), Respond to Vulnerabilities\n(RV). Findings map to PW and RV most often.\n\n| Practice | What it requires | Detector signal |\n|----------|------------------|-----------------|\n| PW.4 | Reuse existing well-secured software | dependencies pinned, scanned, attested |\n| PW.5 | Create source code aligned with secure practices | linter enforces auth/crypto/serialization rules |\n| PW.6 | Configure compilation, build processes, links | RUSTFLAGS hardening, Python `-W error`, reproducible builds |\n| PW.7 | Review and analyze human-readable code | SAST run in CI; findings tracked |\n| PW.8 | Test executable code | fuzz coverage, mutation tests, property tests |\n| PW.9 | Configure software with secure default settings | yaml SafeLoader, TLS verify on, autoescape on |\n| RV.1 | Identify, confirm vulnerabilities on a continuous basis | dependency scanner runs on every push |\n| RV.2 | Assess, prioritize, remediate vulnerabilities | severity policy, SLA per severity |\n| RV.3 | Analyze vulnerabilities to identify root causes | post-incident notes feed PW.4-9 |\n\nThe skill's executive summary lists each practice and whether the\ncodebase has at least one detector firing for it. Coverage <80%\nof PW.4-PW.9 is itself a finding (RV.1 unmet).\n\n## CWE Top 25 (2024) mapping\n\nThe skill prioritizes detectors that map to the CWE Top 25 most\ndangerous software weaknesses. Per-finding citations name the\nspecific CWE, not just \"Top 25.\"\n\n| CWE | Title | Languages most often hit |\n|-----|-------|--------------------------|\n| CWE-79 | Cross-site Scripting | Python, JS |\n| CWE-787 | Out-of-bounds Write | Rust unsafe, C/C++ FFI |\n| CWE-89 | SQL Injection | Python, Rust |\n| CWE-352 | CSRF | Python web frameworks |\n| CWE-22 | Path Traversal | All |\n| CWE-125 | Out-of-bounds Read | Rust unsafe, C/C++ FFI |\n| CWE-78 | OS Command Injection | Python (subprocess), shell scripts |\n| CWE-416 | Use After Free | Rust unsafe, C/C++ |\n| CWE-862 | Missing Authorization | Web layer |\n| CWE-434 | Unrestricted File Upload | Web layer |\n| CWE-94 | Code Injection | Python (eval/exec), template engines |\n| CWE-20 | Improper Input Validation | All |\n| CWE-77 | Command Injection | All shell-out paths |\n| CWE-287 | Improper Authentication | Auth layer |\n| CWE-269 | Improper Privilege Management | Container, sudo |\n| CWE-502 | Deserialization of Untrusted Data | Python, Java |\n| CWE-200 | Exposure of Sensitive Information | Logs, errors, telemetry |\n| CWE-863 | Incorrect Authorization | Web layer |\n| CWE-918 | Server-Side Request Forgery | URL fetchers |\n| CWE-119 | Improper Restriction of Operations within Memory Buffer | Rust unsafe, C/C++ |\n| CWE-476 | NULL Pointer Dereference | Rust unsafe, C/C++ |\n| CWE-798 | Use of Hard-coded Credentials | All |\n| CWE-190 | Integer Overflow or Wraparound | All |\n| CWE-400 | Uncontrolled Resource Consumption | All |\n| CWE-306 | Missing Authentication for Critical Function | Web/API layer |\n\n## OWASP ASVS level targets\n\nFindings track the ASVS level they aim at:\n\n| Level | Target | Skill default |\n|-------|--------|---------------|\n| L1 | Opportunistic attacker | always |\n| L2 | Targeted attacker | when secrets-bearing config detected |\n| L3 | Determined attacker | only on `--focus all` with `--strict` |\n\n## RustSec advisory database\n\nFor Rust findings, cite the specific advisory ID\n(RUSTSEC-YYYY-NNNN). The `cargo audit` JSON output contains\nthese directly. Use them in the proposal's reversal plan to\nexplain *why* the upgrade is required.\n\n## How findings cite\n\nEach finding's `Citation:` line names:\n\n1. Primary CWE (always)\n2. NIST SSDF practice (always; pick the closest match)\n3. Optional: OWASP ASVS section, RustSec ID, PEP number, CVE\n\nExample:\n\n```\nCitation: CWE-502 (Deserialization of Untrusted Data),\nNIST SSDF PW.7 (Review and analyze human-readable code),\nOWASP ASVS V5.5 (Deserialization Prevention).\n```\n\nA finding with no primary CWE cannot be classified above\nADVISORY severity.\n\nFile v1.9.17:modules/proposal-shape.md\n\n# Proposal Shape\n\nEvery proposed remediation in a hardening report follows this\nschema. The schema is not optional: a finding without a complete\nproposal cannot be applied (the user can still choose to file or\ndefer it).\n\n## Required fields\n\n| Field | Purpose |\n|-------|---------|\n| `id` | Stable identifier across runs (e.g., `H7`, `PY03`) |\n| `severity` | CRITICAL / HIGH / MEDIUM / LOW / ADVISORY |\n| `citation` | Primary CWE plus NIST SSDF practice (mandatory) |\n| `file` | Single file the proposal touches (multi-file proposals split into siblings) |\n| `lines` | Affected line range, e.g., `42-58` |\n| `detection_signal` | What pattern the scanner saw (in safe-to-quote form) |\n| `proposal` | One-paragraph description of the fix |\n| `diff` | Concrete diff or config snippet, not \"consider doing X\" |\n| `blast_radius` | low / medium / high — see below |\n| `reversal_plan` | Exact command to revert and the conditions to reapply |\n| `expected_test` | Test path that should pass after the change |\n\n## Severity to default disposition\n\n| Severity | Default disposition |\n|----------|---------------------|\n| CRITICAL | apply or file immediately; never advisory |\n| HIGH | propose for apply with prompt |\n| MEDIUM | propose for apply only when `--auto-apply medium` |\n| LOW | file as issue by default |\n| ADVISORY | report only; never proposed |\n\nCRITICAL findings always prompt even under `--auto-apply`.\n\n## Blast radius scale\n\nThe proposal queries `Skill(pensive:blast-radius)` for the\nchange-impact graph and reports one of:\n\n| Tier | Definition |\n|------|------------|\n| **low** | Single file; no public API change; no signature change; no behavior visible to callers |\n| **medium** | Multiple files OR public API addition (new param with default, new method) OR test-only behavior change |\n| **high** | Public API breaking change OR cross-plugin coupling OR config schema change |\n\nHigh-blast-radius proposals require explicit approval even\nunder `--auto-apply`. The skill warns when the radius rises\nabove the user's current `--auto-apply` ceiling.\n\n## Reversal plan template\n\n```\nReversal:\n  command: git revert <sha> --no-edit\n  retry condition: <when it would be safe to reapply>\n  evidence file: reviews/harden-<date>.md (this report)\n```\n\nFor config changes that cannot be reverted by `git revert`\nalone (e.g., a CI permission change that runs only on push):\n\n```\nReversal:\n  command: git revert <sha> --no-edit\n  follow-up: re-trigger the workflow on master to confirm the\n             permissions are restored\n  evidence file: reviews/harden-<date>.md\n```\n\n## Expected-passing test\n\nEach proposal cites a test that should pass after the change:\n\n- If a test already exists, name it: `tests/unit/x.py::test_y`.\n- If a test must be added, the proposal includes the test code in\n  the same diff block. The test must fail against the\n  pre-proposal code (RED) and pass after (GREEN).\n\nA proposal without an expected test is downgraded to ADVISORY.\nThis is the harden equivalent of `Skill(imbue:proof-of-work)`'s\nIron Law.\n\n## Approval options (per finding)\n\nWhen the approval gate fires, the user gets:\n\n1. **apply** — apply the diff, commit, run gates, advance.\n2. **file** — create a GitHub issue with the proposal body and\n   close out the finding.\n3. **defer** — log to `.harden/backlog.md` for future runs to\n   surface again.\n4. **reject** — record a rejection with optional rationale; the\n   finding will not surface again unless code changes invalidate\n   the rejection.\n\nThe auto-apply ceiling determines which severities skip the gate\nentirely:\n\n```bash\n/harden --auto-apply low      # apply LOW automatically\n/harden --auto-apply medium   # apply LOW + MEDIUM automatically\n/harden --auto-apply high     # apply LOW + MEDIUM + HIGH automatically\n```\n\nCRITICAL is never auto-applied.\n\n## Worked example\n\n```yaml\nid: PY01\nseverity: HIGH\ncitation: \"CWE-502 (Deserialization of Untrusted Data), NIST SSDF PW.7\"\nfile: src/api/loader.py\nlines: 42-44\ndetection_signal: |\n  Module imports the Python stdlib unsafe-deserialization helper\n  and calls its loads() helper on bytes that originate from the\n  request body (data flows from request.body through validate()\n  into loader.loads()).\nproposal: |\n  Replace the unsafe loader call with json.loads. The payload\n  shape is JSON-compatible per the API spec (verified by reading\n  the OpenAPI schema for /v1/upload). This eliminates the\n  arbitrary-code-execution attack path while preserving the\n  positive-path behavior.\ndiff: |\n  --- a/src/api/loader.py\n  +++ b/src/api/loader.py\n  @@ -42,3 +42,5 @@\n  -from <stdlib-unsafe-loader> import loads\n  +import json\n  -    obj = loads(payload)\n  +    obj = json.loads(payload)\nblast_radius: low\nreversal_plan:\n  command: \"git revert <sha> --no-edit\"\n  retry_condition: \"do not retry; the previous form was unsafe by design\"\n  evidence_file: \"reviews/harden-2026-05-10.md\"\nexpected_test: tests/unit/api/test_loader.py::test_round_trip_json\n```\n\n## Multi-file proposals\n\nWhen a hardening fix needs touches across multiple files (e.g.,\nadding a `Tier` `Literal` requires updates in classifiers, the\nDORAMetrics dataclass, and the tests), split into sibling\nproposals (PY01a, PY01b, PY01c) with a shared `parent_id`. The\napproval gate applies them as one unit, but each is its own\ncommit so reverts stay surgical.\n\n## What a proposal must NOT do\n\n- Modify generated code, vendored code, or `node_modules`.\n- Touch the changelog except to add a `### Security` bullet.\n- Bump dependency versions beyond the minimum required for the\n  fix (a separate proposal per dep upgrade).\n- Introduce a new dependency without an `imbue:proof-of-work`\n  evidence trail showing the dep was vetted.\n- Disable existing tests or assertions to make the fix easier.\n\nFile v1.9.17:modules/python-checks.md\n\n# Python Hardening Checks\n\nDetectors for Python codebases. Each row is a discrete check the\nskill runs; each carries a CWE citation for the report.\n\nThe detection-signal column uses placeholder syntax for patterns\nthat the project's pre-commit security hooks block writing\nliterally. The hooks exist for a reason: this doc describes the\nrules, but the regexes themselves live in code where the safety\nreview treats them as data, not source. If a future contributor\nneeds to inspect the literal patterns, see the corresponding\ndetector module under `plugins/pensive/skills/harden/detectors/`\n(future work; not part of the v1 skill).\n\n## Detection ruleset\n\n| ID | Check | CWE | NIST SSDF | Detection signal |\n|----|-------|-----|-----------|------------------|\n| PY01 | Unsafe deserialization (the stdlib `pickle` family, `marshal`, `shelve`) | CWE-502 | PW.5.1 | `<unsafe-loader>.loads(` on bytes you do not control |\n| PY02 | YAML loaded without a safe Loader | CWE-502 | PW.9 | `yaml.load(` without `Loader=SafeLoader` |\n| PY03 | Code injection via `eval`/`exec`/`compile(...,'exec')` | CWE-94 | PW.5.1 | `<eval-family>(` with a non-constant argument |\n| PY04 | Shell-command injection in a child-process call | CWE-78 | PW.5.1 | bandit B602 / B605: child-process helper invoked with the shell-mode flag and a formatted string |\n| PY05 | SQL injection via string formatting | CWE-89 | PW.5.1 | `cursor.execute(f\"...\")` or `% ` formatting in a query |\n| PY06 | Path traversal in user-supplied paths | CWE-22 | PW.5.1 | `open(user_input)` without `Path.resolve()` and `is_relative_to()` |\n| PY07 | Insecure RNG used for security purposes | CWE-330 | PW.5.1 | `import random` then a token/secret/key generated from it; should be `secrets` |\n| PY08 | TLS verification disabled | CWE-295 | PW.9 | `requests.*(verify=False)`, `ssl.CERT_NONE`, `disable_warnings(InsecureRequestWarning)` |\n| PY09 | Hardcoded credentials | CWE-798 | PW.5.1 | regex match for `api[_-]?key`, `secret`, `token`, `passwd` literals; AWS prefixes (`AKIA...`) |\n| PY10 | Subprocess invocation without timeout | CWE-400 | PW.5.1 | `<child-proc>.run/Popen` without `timeout=` |\n| PY11 | Tarfile extraction without member filter | CWE-22 | PW.9 | `tarfile.*extractall(` without `filter=` (PEP 706; default became safe in 3.12+) |\n| PY12 | XML XXE / billion-laughs | CWE-611, CWE-776 | PW.9 | `xml.etree.ElementTree.parse(` (use `defusedxml`) |\n| PY13 | Jinja autoescape off in HTML context | CWE-79 | PW.9 | `Environment(autoescape=False)` or `Markup(user_input)` |\n| PY14 | Logging secrets | CWE-532 | PW.5.1 | `logger.*(token)`, `logger.*(password)`, `logger.*(api_key)` |\n| PY15 | Bare `except:` swallowing errors in security paths | CWE-754 | PW.7 | `except:` or `except Exception: pass` in auth or crypto paths |\n| PY16 | Async TOCTOU (time-of-check / time-of-use) | CWE-367 | PW.5.1 | `await is_authorized(...)` then `await act(...)` without re-check |\n| PY17 | Untrusted format string | CWE-134 | PW.5.1 | `(user_input).format(`, f-string built from user input, `\"%\" % user` |\n| PY18 | Insecure temp file | CWE-377 | PW.5.1 | `tempfile.mktemp(` (use `mkstemp` or `NamedTemporaryFile`) |\n| PY19 | `assert` for runtime auth check | CWE-617 | PW.5.1 | `assert user.is_admin` (assert is stripped under `python -O`) |\n| PY20 | `requests` without timeout | CWE-400 | PW.5.1 | `requests.get/post(...)` without `timeout=` |\n| PY21 | HTTP request smuggling on outdated frameworks | CWE-444 | RV.1 | `gunicorn<22.0.0` (CVE-2024-1135), `aiohttp<3.9.2` (CVE-2024-23829) |\n| PY22 | Multipart resource exhaustion | CWE-400 | RV.1 | `python-multipart<0.0.18` (CVE-2024-47874); FastAPI route without `max_part_size` |\n| PY23 | Weak hashing for passwords or auth tokens | CWE-327, CWE-328 | PW.5.1 | `hashlib.md5`, `hashlib.sha1` reachable from password / session-token paths |\n| PY24 | Missing TLS 1.2 floor | CWE-326 | PW.9 | `ssl.PROTOCOL_TLSv1`, `PROTOCOL_SSLv23` without `minimum_version` |\n| PY25 | Index pinning missing for PyPI consumption | CWE-829 | PW.4 | no `[[tool.uv.index]]` in `pyproject.toml`; no `--index-url` constraint in `requirements.txt` |\n| PY26 | Hash-unpinned installs | CWE-494, NIST SI-7 | PW.4 | `requirements.txt` without `--hash=` lines; missing `uv.lock`/`poetry.lock` |\n| PY27 | PyPI release without PEP 740 attestation | NIST SSDF PS.2.1 | PS.2 | release workflow uses static API token instead of `pypa/gh-action-pypi-publish@release/v1` (Trusted Publishers) |\n\n## Library substitution table\n\nWhen a finding fires, the proposal usually swaps the offending\nlibrary or call. The substitution table:\n\n| Bad | Good | Why |\n|-----|------|-----|\n| the unsafe-deserialization stdlib family | `json` if data is JSON-shaped, otherwise `msgspec` / `pydantic` | safe-by-default deserialization |\n| `yaml.load(...)` | `yaml.safe_load(...)` (or `ruamel.yaml.YAML(typ='safe')`) | rejects arbitrary tag construction |\n| `eval`, `exec` | `ast.literal_eval` for constants; otherwise refactor to a typed parser | no code path executes user input |\n| `random.{choice,token_bytes,...}` for security | `secrets.token_bytes/urlsafe`, `secrets.choice` | CSPRNG-backed |\n| `xml.etree.ElementTree` on untrusted input | `defusedxml.ElementTree` | XXE / billion-laughs hardened |\n| `urllib.request.urlopen` | `requests` (`timeout=`, `verify=True`) or `httpx` (defaults are safer) | timeout-by-default |\n| `tempfile.mktemp` | `tempfile.NamedTemporaryFile(delete=False)` | atomic creation |\n| `assert is_authorized()` | explicit `if not is_authorized(): raise PermissionError(...)` | survives `python -O` |\n| `hashlib.md5/sha1` for passwords | `argon2-cffi`, `bcrypt`, or `passlib` | KDF with cost factor |\n| static API tokens for PyPI | PyPI Trusted Publishers and sigstore attestation (PEP 740) | revocable, log-traceable, no shared secret |\n\n## Static-analyzer integration\n\nRun the canonical Python security tools and treat their findings\nas first-class harden findings:\n\n```bash\n# Bandit ruleset (PyCQA-maintained AST scanner)\nuv run bandit -r src/ -f json -o /tmp/harden-bandit.json\n\n# pip-audit on the lockfile (PyPA + Trail of Bits, OSV-backed)\nuv run pip-audit --lockfile uv.lock --format json > /tmp/harden-pipaudit.json\n\n# osv-scanner reads pyproject + lockfiles + Cargo.lock\nosv-scanner --format json . > /tmp/harden-osv.json\n\n# semgrep with the security-audit ruleset\nsemgrep --config=p/python --json --output=/tmp/harden-semgrep.json\n```\n\nFindings from these tools convert to the harden schema by joining\non file:line and severity. A bandit B301 finding (the unsafe\ndeserialization rule) becomes the same finding shape as the\ninternal PY01 detector, so the report does not double-count.\n\n## Frontier Python concerns (2025-2026)\n\nLoaded from `frontier-checks.md` for full coverage. Brief list:\n\n- PEP 740 sigstore attestations on PyPI (verify before install);\n  see Trail of Bits' \"Attestations: a new generation of\n  signatures on PyPI\" (Nov 2024).\n- Tarfile member filter (PEP 706) — `tarfile.data_filter` default\n  in Python 3.12+; verify the codebase does not still pass\n  `filter=None`.\n- pyproject.toml `[[tool.uv.index]]` priority pinning to defeat\n  dependency confusion attacks.\n- LLM SDK prompt-injection patterns and MCP server hardening\n  (CWE-1426; OWASP LLM Top 10 #01, #02).\n- ASGI middleware request smuggling (CVE-2024-23829 class).\n- Sandboxing application code: WASM (Pyodide), gVisor, nsjail.\n- Slopsquatting / package hallucination (arXiv 2406.10279):\n  LLM-suggested non-existent packages later registered as\n  malware. Mitigation: lockfile and `--require-hashes` and human\n  review on every dep addition.\n\n## Output schema\n\nEach Python finding follows the schema in\n`modules/proposal-shape.md`. The detection-signal text uses safe\nplaceholders so the doc itself does not trip secret-scanners or\nthe project's security pre-commit hooks; the actual scanner emits\nthe literal pattern with file:line context in the report.\n\nFile v1.9.17:modules/rust-checks.md\n\n# Rust Hardening Checks\n\nDetectors for Rust codebases. The Rust ecosystem ships strong\ndefault safety; the harden skill verifies the discipline is\nactually applied and the supply chain is curated.\n\nFor a deep ownership/unsafe audit, the skill defers to\n`Skill(pensive:rust-review)`. This module focuses on the\nhardening posture (capability use, supply-chain hygiene,\nside-channel defense) and frontier 2025-2026 practices.\n\n## Detection ruleset\n\n| ID | Check | CWE / RustSec | NIST SSDF | Detection signal |\n|----|-------|---------------|-----------|------------------|\n| RS01 | Crate root lacks `#![forbid(unsafe_code)]` and does not declare audited unsafe | CWE-119 | PW.5 | `lib.rs`/`main.rs` without forbid; no `audit/unsafe.md` |\n| RS02 | Unsafe block without `// SAFETY:` comment | CWE-119 | PW.7 | `unsafe {` not preceded by `// SAFETY:` line |\n| RS03 | `unwrap()` / `expect()` on caller-supplied data | CWE-754 | PW.5 | `.unwrap()` after `parse()`, `from_str`, `serde::from_*` on external input |\n| RS04 | `panic!` reachable from request handler | CWE-754 | PW.5 | `panic!`, `unimplemented!`, `unreachable!` on user-input branches |\n| RS05 | `cargo audit` not wired to CI | RV.1 | RV.1 | no `cargo audit` step in `.github/workflows/*.yml` |\n| RS06 | `cargo deny` config missing or not enforced | RV.1 | PW.4 | no `deny.toml` or CI step missing |\n| RS07 | `cargo vet` audits stale / missing for new deps | RV.2 | PW.4 | `supply-chain/audits.toml` does not cover new entries in `Cargo.lock` |\n| RS08 | Comparing secrets with `==` | CWE-208 | PW.5 | `==` between `&[u8]` typed as token/secret/digest; should be `subtle::ConstantTimeEq` |\n| RS09 | Secrets not zeroized on drop | CWE-316 | PW.5 | secret-typed struct without `Zeroize`/`ZeroizeOnDrop` |\n| RS10 | Async cancellation un-safe | CWE-362 | PW.5 | `tokio::select!` arms with non-cancel-safe futures (e.g., `BufReader::read_to_end`) |\n| RS11 | `Mutex::lock().unwrap()` in hot path | CWE-754 | PW.5 | poisoned-lock unwrap reachable from public API |\n| RS12 | Source replacement to private registry without integrity pin | CWE-494 | PW.4 | `[source.crates-io]` `replace-with` without checksum |\n| RS13 | Git dependency without `rev=` | CWE-494 | PW.4 | `git = \"...\"` without `rev = \"...\"` (mutable target) |\n| RS14 | Build script (`build.rs`) reads files outside `OUT_DIR` | CWE-829 | PW.6 | `build.rs` opens path containing `..` |\n| RS15 | `serde(deny_unknown_fields)` missing on auth-bearing structs | CWE-1287 | PW.5 | struct deriving `Deserialize` for an auth/config payload without `#[serde(deny_unknown_fields)]` |\n| RS16 | Compiler hardening flags absent | CWE-1244 | PW.6 | `.cargo/config.toml` missing `RUSTFLAGS` for stack protection / CFI |\n| RS17 | `unsafe impl Send/Sync` without proof | CWE-362 | PW.7 | `unsafe impl (Send|Sync) for ...` without SAFETY comment |\n| RS18 | FFI without bounds annotation | CWE-787 | PW.5 | `extern \"C\"` function with `*const T` / `*mut T` arg with no length param |\n\n## Tooling integration\n\n```bash\n# Vulnerability scan against RustSec advisory DB\ncargo audit --json > /tmp/harden-cargo-audit.json\n\n# Policy enforcement (license, advisory, source, ban list)\ncargo deny check --format json 2>/tmp/harden-deny.json\n\n# Cryptographic-supply-chain audit\ncargo vet check 2>&1 | tee /tmp/harden-vet.log\n\n# Unsafe block inventory (third-party tool; requires install)\ncargo geiger --output-format json > /tmp/harden-geiger.json\n\n# Mutation testing (high-leverage; expensive)\ncargo mutants --in-diff origin/main..HEAD --no-times --json\n```\n\nThe harden report joins these on file:line and advisory ID.\n\n## Capability-style hardening (frontier 2025-2026)\n\n| From | To | Why |\n|------|-----|-----|\n| `std::fs` ambient access | `cap-std::fs::Dir` capability | filesystem ops require an explicit handle, not a path |\n| raw `socket`/`std::net` | `cap-std::net` | network endpoints are capabilities, not strings |\n| environment-driven config | `secrecy::SecretString` for secrets | wrapper prevents `Debug`/`Display` leaks |\n| ad-hoc retry loops | `tower::retry` with backoff and budget | bounded resource consumption (CWE-400) |\n\nThese are recommendations, not blocking findings — surface in\nthe report as MEDIUM advisories with the rationale in the\nproposal.\n\n## Concurrency hardening\n\n| Pattern | Replace with | Reason |\n|---------|--------------|--------|\n| naked `std::sync::Mutex` in hot path | `parking_lot::Mutex` (no poisoning, smaller, faster) | reduces unwrap-on-poison footguns |\n| ad-hoc `Arc<Mutex<HashMap>>` | `dashmap::DashMap` | lock-free reads, sharded writes |\n| `tokio::sync::Mutex` held across `await` | `parking_lot::Mutex` for short critical sections | avoid tokio scheduler stalls |\n| `loom`-untested concurrent code | wire `cargo test --features loom` for lock-free types | model-checks all interleavings |\n\n## Compiler hardening flags\n\nIn `.cargo/config.toml`:\n\n```toml\n[target.'cfg(all())']\nrustflags = [\n    # Stack-smashing protection\n    \"-C\", \"force-frame-pointers=yes\",\n    # Disable sources of UB\n    \"-D\", \"warnings\",\n    # Treat unsafe-op-without-unsafe-fn as error in 2024 edition\n    \"-D\", \"unsafe_op_in_unsafe_fn\",\n]\n```\n\nFor sanitizer-instrumented test runs:\n\n```bash\nRUSTFLAGS=\"-Z sanitizer=address\" cargo +nightly test --target x86_64-unknown-linux-gnu\n```\n\n## Output schema\n\nSame as `python-checks.md`. Each Rust finding emits a single\nproposal with diff, blast radius, reversal plan, and expected\ntest. RustSec IDs go in the citation column when applicable.\n\nFile v1.9.17:skill-card.md\n\n## Description: <br>\nApplies NIST/CWE security hardening to Python and Rust code. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[athola](https://clawhub.ai/user/athola) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and engineers use this skill to audit a repository for security hardening gaps, map findings to NIST SSDF and CWE references, and prepare concrete remediation proposals for approval. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: Broad triggers may activate the hardening workflow outside a planned audit. <br>\nMitigation: Invoke the skill deliberately for repository audits and review its planned actions before allowing changes. <br>\nRisk: Remediation proposals may modify files, create commits, open issues, or comment on pull requests. <br>\nMitigation: Require user approval for proposed actions and re-run project gates after approved changes. <br>\nRisk: Security findings or fixes may be incorrect for the target repository context. <br>\nMitigation: Review each finding's citation, affected file, diff, blast radius, reversal plan, and expected test before applying it. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill page](https://clawhub.ai/athola/skills/nm-pensive-harden) <br>\n- [ClawHub metadata homepage](https://github.com/athola/claude-night-market/tree/master/plugins/pensive) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, markdown, code, shell commands, configuration, guidance] <br>\n**Output Format:** [Markdown reports with findings tables, remediation proposals, diffs or configuration snippets, shell commands, and validation guidance.] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [May propose file changes, commits, issue creation, or PR comments after user approval.] <br>\n\n## Skill Version(s): <br>\n1.9.17 (source: server release evidence) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v1.9.16: 9 files, 23344 bytes\n\nFiles: modules/cross-cutting.md (5415b), modules/frontier-checks.md (5056b), modules/nist-controls.md (4262b), modules/proposal-shape.md (5761b), modules/python-checks.md (7917b), modules/rust-checks.md (5491b), skill-card.md (2606b), SKILL.md (10269b), _meta.json (137b)\n\nFile v1.9.16:SKILL.md\n\n---\nname: harden\ndescription: Applies NIST/CWE security hardening to Python and Rust code\nversion: 1.9.8\ntriggers:\n  - security\n  - hardening\n  - nist\n  - supply-chain\n  - python\n  - rust\n  - cwe\n  - auditing code for vulnerabilities or proposing concrete security remediations\nmetadata: {\"openclaw\": {\"homepage\": \"https://github.com/athola/claude-night-market/tree/master/plugins/pensive\", \"emoji\": \"\\ud83d\\udd12\", \"requires\": {\"config\": [\"night-market.pensive:safety-critical-patterns\", \"night-market.pensive:rust-review\", \"night-market.pensive:bug-review\", \"night-market.pensive:tiered-audit\", \"night-market.pensive:blast-radius\", \"night-market.leyline:supply-chain-advisory\", \"night-market.leyline:authentication-patterns\", \"night-market.leyline:content-sanitization\", \"night-market.abstract:hook-authoring\", \"night-market.imbue:proof-of-work\"]}}}\nsource: claude-night-market\nsource_plugin: pensive\n---\n\n> **Night Market Skill** — ported from [claude-night-market/pensive](https://github.com/athola/claude-night-market/tree/master/plugins/pensive). For the full experience with agents, hooks, and commands, install the Claude Code plugin.\n\n\n# Harden Codebase Skill\n\nActive security hardening — scan the existing repository for\nvulnerabilities and forward-facing threats, then propose concrete\nremediations the user can approve, defer, or file.\n\nThis skill is the engine behind `/harden`. It complements the\nClaude Code built-in `/security-review` (which scans the pending\ndiff) by sweeping the whole repository against citation-backed\nchecks rather than line-level review of in-flight code.\n\n## When To Use\n\n- Quarterly security-posture audits.\n- Before tagging a release that touches sensitive code paths.\n- After a published advisory affects the language ecosystem.\n- When onboarding a new repository and want a baseline.\n- After integrating a new dependency or upstream service.\n\n## When NOT To Use\n\n- Pending-diff review on a single PR. Use `/security-review`.\n- Architecture-level threat modeling. Use `attune:war-room`\n  with a security-focused panel.\n- Cryptographic protocol review. The skill flags suspect crypto\n  but does not propose protocol fixes (specialist work).\n- One-off bug hunting. Use `pensive:bug-review`.\n\n## Required TodoWrite Items\n\n1. `harden:discovery` — inventory languages, build files, hooks,\n   CI workflows\n2. `harden:scan-python` — run python-checks.md detectors when\n   Python is present\n3. `harden:scan-rust` — run rust-checks.md detectors when Rust\n   is present\n4. `harden:scan-cross-cutting` — run cross-cutting.md detectors\n   (deps, secrets, SBOM, CI)\n5. `harden:scan-frontier` — run frontier-checks.md (PQC, LLM\n   supply chain, sandboxing)\n6. `harden:nist-mapping` — map findings to NIST SSDF practices\n7. `harden:proposals` — for each finding above the threshold,\n   draft a concrete remediation per `modules/proposal-shape.md`\n8. `harden:approval-gate` — present proposals to the user for\n   apply / file / defer / reject\n9. `harden:apply-and-validate` — apply approved proposals as\n   discrete commits, re-run gates, capture evidence\n10. `harden:report` — write `reviews/harden-<date>.md` and\n    optionally post to Discussions\n\n## Progressive Loading\n\nLoad modules based on what the discovery step finds.\n\n| Detected | Load |\n|----------|------|\n| Python files (`*.py`, `pyproject.toml`) | `modules/python-checks.md` |\n| Rust files (`*.rs`, `Cargo.toml`) | `modules/rust-checks.md` |\n| Any | `modules/nist-controls.md` (citation backbone) |\n| Any | `modules/cross-cutting.md` (deps, secrets, CI) |\n| LLM SDK use (`anthropic`, `openai`), MCP server, post-quantum surface | `modules/frontier-checks.md` |\n| Any with proposals enabled | `modules/proposal-shape.md` |\n\nThe module hub keeps the SKILL.md itself under the\n`estimated_tokens: 1100` budget. Detail lives in the modules.\n\n## Core Workflow\n\n### Phase 1 — Discovery\n\nInventory the repo without modifying anything:\n\n```bash\n# Languages and build files\nfind . -type f \\( -name '*.py' -o -name '*.rs' -o -name '*.sh' \\) \\\n  | head -200 > /tmp/harden-langs.txt\n\n# Build manifests\nls pyproject.toml Cargo.toml package.json go.mod 2>/dev/null\n\n# CI workflows and pre-commit\nls .github/workflows/ .pre-commit-config.yaml 2>/dev/null\n\n# Hooks and Dockerfiles\nfind . -path ./node_modules -prune -o -type f \\\n  \\( -name 'hooks.json' -o -name 'Dockerfile*' \\) -print\n```\n\nDispatch `/discovery-prefilter` if the repo has > 5000 source files\nto bound the scan.\n\n### Phase 2 — Citation-backed scan\n\nFor each detected language, load the matching module and run its\ndetector list. Each detector outputs findings with the schema\ndefined in `modules/proposal-shape.md`. The citation column is\nmandatory: a finding without a NIST/CWE reference is downgraded\nto \"advisory\" and not eligible for active proposal.\n\n### Phase 3 — NIST mapping\n\nGroup findings by SSDF practice (PW.4, PW.8, RV.1, etc.) and CWE\nID. The mapping table lives in `modules/nist-controls.md`. The\nreport's executive summary references SSDF practice coverage so\nthe audit is comparable across runs.\n\n### Phase 4 — Proposal generation\n\nFor each finding above the configured severity threshold, draft a\nconcrete remediation per `modules/proposal-shape.md`:\n\n- Specific files and lines touched\n- Diff or config snippet (not \"consider doing X\")\n- Blast-radius assessment via `pensive:blast-radius`\n- Reversal plan: how to revert if the change breaks behavior\n- Test that should pass after the change\n\n### Phase 5 — Approval gate\n\nPresent proposals one at a time via `AskUserQuestion`. Default\noptions: **apply**, **file as issue**, **defer to backlog**,\n**reject**. Auto-apply is opt-in via the `--auto-apply` flag and\nrespects a per-finding severity threshold.\n\n### Phase 6 — Apply and validate\n\nApply each approved proposal as a discrete commit:\n\n```bash\ngit add <touched files>\ngit commit -m \"harden: <finding-id> <one-line summary>\"\n```\n\nAfter each apply, re-run the project gates:\n\n```bash\nmake test --quiet && make lint && make type-check\n```\n\nIf a gate fails, revert the commit (`git revert HEAD --no-edit`)\nand downgrade the finding to \"needs human design.\"\n\n### Phase 7 — Report\n\nWrite `reviews/harden-<date>.md` with:\n\n- Executive summary (SSDF practice coverage, CWE distribution)\n- Findings table grouped by severity\n- Per-finding detail: detection signal, citation, proposal, status\n- Disposition table (applied / filed / deferred / rejected)\n- Re-run instructions\n\nIf running inside a PR context, post the executive summary as a\ncomment via `abstract:post_review_insights`.\n\n## Severity Classification\n\n| Severity | Definition | Default disposition |\n|----------|------------|---------------------|\n| **CRITICAL** | Active exploit path, RCE, credential leak | apply or file immediately |\n| **HIGH** | Plausible exploit, missing defense-in-depth on attack surface | propose for apply |\n| **MEDIUM** | Best-practice gap, hardening opportunity | propose for apply with `--auto-apply medium` |\n| **LOW** | Style/documentation gap with security flavor | file as issue |\n| **ADVISORY** | Pattern detected without exploit narrative | report only |\n\n## Output Format\n\n```markdown\n# Hardening Report — <date>\n\n## Executive Summary\n\n- Codebase: <repo> @ <sha>\n- Languages scanned: Python (X files), Rust (Y files)\n- NIST SSDF practices covered: PW.4, PW.7, PW.8, RV.1, RV.2\n- CWE Top 25 hits: <count> across <distinct CWEs>\n- Disposition: <N> applied, <N> filed, <N> deferred, <N> rejected\n\n## Findings\n\n| ID | Severity | Citation | File:Line | Disposition |\n|----|----------|----------|-----------|-------------|\n| H1 | CRITICAL | CWE-502, NIST SSDF PW.7 | `src/x.py:45` | applied (commit abc123) |\n| H2 | HIGH | CWE-89, NIST SSDF PW.4 | `src/y.py:120` | filed (#456) |\n\n## Per-finding detail\n\n### H1 — Unsafe deserialization\n\n**Citation:** CWE-502 (Deserialization of Untrusted Data),\nNIST SSDF PW.7 (Review and analyze human-readable code).\n\n**Detection signal:**\n- File: `src/x.py:45`\n- Pattern: <module>.loads(user_supplied_input)\n- Reachability: untrusted, comes from request body\n\n**Proposal:** ...\n\n**Blast radius:** ...\n\n**Reversal plan:** ...\n```\n\n## Safety Rails\n\n- **Never apply without approval.** Even with `--auto-apply`,\n  CRITICAL findings always prompt.\n- **One finding per commit.** Reversals are per-finding, not\n  per-batch.\n- **Re-run gates after each apply.** A gate failure reverts the\n  commit and downgrades the finding.\n- **Citation is mandatory.** Findings without a NIST/CWE/RustSec\n  reference are advisory only and skip the apply phase.\n- **Read-only on first run.** First invocation defaults to\n  `--report-only` until the user has reviewed at least one\n  report and explicitly opts into proposals.\n\n## Integration\n\nThe skill composes (rather than re-implements):\n\n- `pensive:rust-review` — full Rust audit when Rust is present\n- `pensive:bug-review` — bug-hunting backbone\n- `pensive:safety-critical-patterns` — NASA Power-of-10 adapted\n- `pensive:tiered-audit` — three-tier discipline (`--tier 1/2/3`)\n- `pensive:blast-radius` — change-impact assessment for proposals\n- `leyline:supply-chain-advisory` — dependency posture\n- `leyline:authentication-patterns` — auth/credential review\n- `leyline:content-sanitization` — input handling\n- `abstract:hook-authoring` — hook-event security\n- `imbue:proof-of-work` — evidence discipline for findings\n\n## Exit Criteria\n\n- [ ] Discovery output lists every language and build manifest\n      detected in the repo.\n- [ ] Each finding carries a CWE or NIST SSDF citation; the\n      report executive summary lists the SSDF practice coverage.\n- [ ] Each finding above the severity threshold has a concrete\n      proposal (file, diff or config snippet, blast radius,\n      reversal plan, expected-passing test).\n- [ ] No proposal was applied without explicit user approval\n      (or without an `--auto-apply` flag covering its severity).\n- [ ] Each applied proposal is its own commit, reversal-friendly.\n- [ ] After every apply, the project gates were re-run; any\n      gate failure reverted the commit and downgraded the\n      finding.\n- [ ] `reviews/harden-<date>.md` exists and lists every finding\n      with a disposition (applied / filed / deferred / rejected /\n      advisory).\n\nFile v1.9.16:_meta.json\n\n{\n  \"ownerId\": \"kn7d107jg9jv602h9ytsegydq184a42s\",\n  \"slug\": \"nm-pensive-harden\",\n  \"version\": \"1.9.16\",\n  \"publishedAt\": 1784058943255\n}\n\nFile v1.9.16:modules/cross-cutting.md\n\n# Cross-Cutting Hardening Checks\n\nChecks that apply regardless of the source language: dependency\nposture, secret hygiene, CI/CD chain, container shape, and the\nSBOM.\n\n## Dependency posture (composes leyline:supply-chain-advisory)\n\n| ID | Check | CWE / NIST | Detection |\n|----|-------|------------|-----------|\n| DEP01 | Lockfile committed | PW.4 | absence of `uv.lock` / `Cargo.lock` / `package-lock.json` |\n| DEP02 | Dependency scanner runs in CI | RV.1 | no `pip-audit`/`cargo audit`/`npm audit` step in workflows |\n| DEP03 | Known-bad versions blocked | CWE-829 | `leyline:supply-chain-advisory` blocklist not consulted |\n| DEP04 | Auto-update bot configured | RV.1 | no `dependabot.yml` / `renovate.json` |\n| DEP05 | Direct deps pinned to exact versions | CWE-494 | `^1.2` / `~1.2` / `1.2.*` for security-critical deps |\n| DEP06 | Hash-pinned for top-tier supply-chain trust | CWE-494 | `--require-hashes` not used in `pip` / `requirements.txt` |\n| DEP07 | License policy enforced | none | no `cargo deny` license rules / no `pip-licenses` check |\n\n## Secret hygiene\n\n| ID | Check | CWE | Detection |\n|----|-------|-----|-----------|\n| SEC01 | Pre-commit secret scanner installed | CWE-798 | no `gitleaks` / `trufflehog` / `talisman` in `.pre-commit-config.yaml` |\n| SEC02 | `.env` files git-ignored | CWE-200 | `.env` tracked or unmatched in `.gitignore` |\n| SEC03 | Long-lived secrets in CI | CWE-798 | `secrets.SOME_KEY` used without `if: github.event_name != 'pull_request'` |\n| SEC04 | OIDC publishing configured | CWE-798 | PyPI/Cargo publish step uses `password:` rather than OIDC `id-token: write` |\n| SEC05 | Audit trail for secret access | PW.7 | repo settings: secret-access logs not retained |\n| SEC06 | Sealed-secrets / secret manager | CWE-798 | secrets baked into config files instead of fetched from a manager |\n\n## CI/CD chain (GitHub Actions example)\n\n| ID | Check | NIST SSDF | Detection |\n|----|-------|-----------|-----------|\n| CI01 | Third-party actions pinned by SHA, not tag | PW.4 | `uses: foo/bar@v1` instead of `@<full SHA>` |\n| CI02 | `permissions:` block per workflow | PW.4 | top-level `permissions:` missing or `permissions: write-all` |\n| CI03 | `GITHUB_TOKEN` minimum scope | PW.4 | default permissions used when `contents: read` would suffice |\n| CI04 | Concurrency cancel for stale runs | RV.2 | no `concurrency.cancel-in-progress: true` |\n| CI05 | Workflow dispatch requires approval for protected branches | PW.4 | branch protection allows direct dispatch |\n| CI06 | SLSA provenance generated for releases | RV.2 | release workflow does not invoke `slsa-framework/slsa-github-generator` |\n| CI07 | SBOM generated and attached to releases | RV.2 | release workflow lacks `cyclonedx`/`syft`/`spdx-sbom-generator` step |\n\n## Container hardening (when Dockerfiles exist)\n\n| ID | Check | CWE | Detection |\n|----|-------|-----|-----------|\n| CO01 | Non-root `USER` set | CWE-269 | `USER root` or `USER` directive missing |\n| CO02 | `FROM` is digest-pinned | CWE-494 | `FROM ubuntu:22.04` instead of `FROM ubuntu@sha256:...` |\n| CO03 | Distroless or slim base for production | PW.4 | `FROM ubuntu:latest` / `FROM debian:latest` for runtime image |\n| CO04 | Read-only root filesystem in compose | CWE-269 | `read_only: true` not set |\n| CO05 | seccomp/apparmor profile referenced | CWE-269 | runtime config lacks profile |\n| CO06 | Multi-stage build to drop build deps | CWE-665 | single-stage `FROM` keeps `gcc`, `make`, etc. in runtime |\n| CO07 | `HEALTHCHECK` defined | none | no liveness signal (operational hygiene) |\n\n## SBOM and provenance\n\n```bash\n# CycloneDX SBOM for the whole repo\nsyft . -o cyclonedx-json > sbom.cdx.json\n\n# SPDX SBOM (alternative format)\nsyft . -o spdx-json > sbom.spdx.json\n\n# Verify against the in-toto attestation if released\ncosign verify-attestation --type slsaprovenance \\\n  --certificate-identity-regexp '.*' --certificate-oidc-issuer-regexp '.*' \\\n  ghcr.io/<org>/<image>:<tag>\n```\n\nThe hardening report includes an SBOM-coverage row: present /\nabsent for each release artifact in the repo.\n\n## Pre-commit security suite\n\nThe skill proposes adding (or extending) `.pre-commit-config.yaml`\nwith:\n\n```yaml\nrepos:\n  - repo: https://github.com/PyCQA/bandit\n    rev: 1.7.10\n    hooks:\n      - id: bandit\n        args: [\"-c\", \"pyproject.toml\"]\n        additional_dependencies: [\"bandit[toml]\"]\n  - repo: https://github.com/gitleaks/gitleaks\n    rev: v8.21.2\n    hooks:\n      - id: gitleaks\n  - repo: https://github.com/Yelp/detect-secrets\n    rev: v1.5.0\n    hooks:\n      - id: detect-secrets\n        args: [\"--baseline\", \".secrets.baseline\"]\n```\n\nIf `cargo` is on PATH:\n\n```yaml\n  - repo: local\n    hooks:\n      - id: cargo-deny\n        name: cargo deny\n        entry: cargo deny check\n        language: system\n        files: 'Cargo\\.(toml|lock)$'\n```\n\n## Severity defaults\n\n| Family | Default | Justification |\n|--------|---------|---------------|\n| DEP04, DEP07, CI07, CO07 | LOW | operational hygiene; no exploit narrative |\n| DEP01, DEP02, SEC01, SEC02, CI02, CI03, CO01, CO02 | MEDIUM | one defense-in-depth layer missing |\n| DEP03, SEC03, SEC04, CI01, CI06, CO03 | HIGH | exploitable supply-chain or privilege issue |\n| SEC03 with leaked active credential | CRITICAL | active exploit path |\n\nA finding can be promoted from default with evidence (e.g.,\nDEP01 promoted to HIGH if the lockfile is missing AND auto-merge\nis enabled on dep PRs).\n\nFile v1.9.16:modules/frontier-checks.md\n\n# Frontier Hardening Checks (2025-2026)\n\nForward-facing checks that defend against threats just emerging\nin production. Findings here are usually MEDIUM by default\nbecause exploitation is non-trivial; promote to HIGH when the\ncodebase has a high-value attack surface (auth provider, signing\nservice, data plane).\n\n## Post-quantum migration readiness\n\nThe NSA CNSA 2.0 timeline targets quantum-resistant crypto for\nNSS by 2030; PCI DSS 4.0.1 expects an inventory by 2026. Most\napplication code is not the right place to swap algorithms, but\nthe *crypto-agility* posture is.\n\n| ID | Check | Citation | Detection |\n|----|-------|----------|-----------|\n| PQ01 | Signing/verification has a single hard-coded algorithm | NIST IR 8547 | `algorithms = [\"RS256\"]` or `algorithms = [\"EdDSA\"]` literal in JWT/JWS code |\n| PQ02 | Algorithm selection driven by config, not code | NIST IR 8547 | move the algorithm list behind a `signing_algorithms` config field |\n| PQ03 | Inventory of crypto APIs in the repo | NIST CNSA 2.0 | no `docs/crypto-inventory.md` or equivalent |\n| PQ04 | TLS clients accept algorithm downgrade silently | CWE-757 | `requests` / `reqwest` defaults without minimum-TLS pin |\n\nThe proposal for PQ02 is usually a small refactor: move\n`algorithms = [\"EdDSA\"]` into a config table the operator can\noverride. The skill does not propose ML-DSA / Falcon migration\nin application code (still specialist work).\n\n## LLM and agentic supply chain\n\nA new failure mode in 2025: AI assistants suggest dependencies\nthat look plausible but do not exist (or are typosquats). The\nchecks below defend the development pipeline itself.\n\n| ID | Check | Citation | Detection |\n|----|-------|----------|-----------|\n| LLM01 | Index pinning to defeat dependency confusion | OWASP LLM Top 10 #08 | `pyproject.toml` lacks `[[tool.uv.index]]` priority order |\n| LLM02 | New deps require human review | OWASP LLM Top 10 #08 | no CI rule blocking auto-merge on dep PRs |\n| LLM03 | LLM SDK calls validate role/instruction boundaries | OWASP LLM Top 10 #01 | system prompt concatenated with user input without separator/role |\n| LLM04 | Tool-use response sanitization | OWASP LLM Top 10 #02 | tool output rendered to UI/terminal without escape |\n| LLM05 | MCP server allowlist of tools | OWASP LLM Top 10 #02 | MCP config mounts every tool from a server (no allowlist) |\n| LLM06 | Agent action audit trail | OWASP LLM Top 10 #06 | no log of tool invocations with inputs |\n\n## Sandbox / isolation posture\n\nFor codebases that execute user-supplied or AI-supplied code:\n\n| ID | Check | Why | Today's option |\n|----|-------|-----|----------------|\n| SB01 | User code runs in same process as host | host privilege escalation | Pyodide WASM (Python), wasmtime (Rust) |\n| SB02 | Network egress unrestricted from sandbox | data exfiltration | gVisor egress policy, NetworkPolicy in K8s |\n| SB03 | Filesystem capabilities ambient | path-based attacks | `cap-std` (Rust), bind-mount only required dirs |\n| SB04 | Resource limits absent | DoS via runaway workload | cgroup `memory.max`, `cpu.max`; `prlimit` in containers |\n\n## eBPF / runtime security hooks\n\nProduction codebases benefit from runtime monitoring even when\nthe static defenses are good. The skill flags absence:\n\n| ID | Check | Tool | What it catches |\n|----|-------|------|-----------------|\n| RT01 | Runtime detection layer present | Falco / Tetragon / Tracee | unexpected syscalls, container escapes |\n| RT02 | App emits structured audit events | OpenTelemetry traces with semantic conventions | post-incident reconstruction |\n| RT03 | Deployment includes seccomp/apparmor profile | runtime config | exploit blast-radius capping |\n\n## Differential-privacy / PETs awareness\n\nFor codebases that handle aggregable user data (analytics, ML\ntraining, telemetry):\n\n| ID | Check | Citation | Signal |\n|----|-------|----------|--------|\n| DP01 | Aggregations expose per-user values without noise | NIST SP 800-188 | counts/means published without DP budget |\n| DP02 | Logs retain raw PII beyond retention window | GDPR Art. 5 | log retention config absent or > 30 days for PII fields |\n\n## Memory-safety migration triage (when C/C++ is present)\n\nPer CISA's \"Secure by Design\" pledge and the ONCD memory-safety\nreport (Feb 2024), new code in safety-critical contexts should\nbe in a memory-safe language by default. The skill flags the\nopportunity, not the migration:\n\n| ID | Check | Signal | Proposal |\n|----|-------|--------|----------|\n| MS01 | C/C++ code paths handle untrusted input | parser, network code in C/C++ | rewrite or wrap behind a Rust shim |\n| MS02 | C-style string handling | `strcpy`, `sprintf`, `gets` | move to Rust or use `safestr`/`absl::Cord` |\n\n## Output\n\nFindings here use the same schema as the other modules. Severity\nis **MEDIUM** by default; promote to HIGH when:\n\n- The repo is an auth/signing/credentialing service (PQ findings)\n- The repo ships an MCP server or agent harness (LLM findings)\n- The repo has untrusted-code-exec posture (SB findings)\n- The repo handles regulated PII (DP findings)\n\nFile v1.9.16:modules/nist-controls.md\n\n# NIST and CWE Citation Backbone\n\nEvery finding in a hardening report carries a citation. This\nmodule is the lookup table.\n\n## NIST SSDF (SP 800-218) practice mapping\n\nThe Secure Software Development Framework defines four practice\ngroups: Prepare the Organization (PO), Protect Software (PS),\nProduce Well-Secured Software (PW), Respond to Vulnerabilities\n(RV). Findings map to PW and RV most often.\n\n| Practice | What it requires | Detector signal |\n|----------|------------------|-----------------|\n| PW.4 | Reuse existing well-secured software | dependencies pinned, scanned, attested |\n| PW.5 | Create source code aligned with secure practices | linter enforces auth/crypto/serialization rules |\n| PW.6 | Configure compilation, build processes, links | RUSTFLAGS hardening, Python `-W error`, reproducible builds |\n| PW.7 | Review and analyze human-readable code | SAST run in CI; findings tracked |\n| PW.8 | Test executable code | fuzz coverage, mutation tests, property tests |\n| PW.9 | Configure software with secure default settings | yaml SafeLoader, TLS verify on, autoescape on |\n| RV.1 | Identify, confirm vulnerabilities on a continuous basis | dependency scanner runs on every push |\n| RV.2 | Assess, prioritize, remediate vulnerabilities | severity policy, SLA per severity |\n| RV.3 | Analyze vulnerabilities to identify root causes | post-incident notes feed PW.4-9 |\n\nThe skill's executive summary lists each practice and whether the\ncodebase has at least one detector firing for it. Coverage <80%\nof PW.4-PW.9 is itself a finding (RV.1 unmet).\n\n## CWE Top 25 (2024) mapping\n\nThe skill prioritizes detectors that map to the CWE Top 25 most\ndangerous software weaknesses. Per-finding citations name the\nspecific CWE, not just \"Top 25.\"\n\n| CWE | Title | Languages most often hit |\n|-----|-------|--------------------------|\n| CWE-79 | Cross-site Scripting | Python, JS |\n| CWE-787 | Out-of-bounds Write | Rust unsafe, C/C++ FFI |\n| CWE-89 | SQL Injection | Python, Rust |\n| CWE-352 | CSRF | Python web frameworks |\n| CWE-22 | Path Traversal | All |\n| CWE-125 | Out-of-bounds Read | Rust unsafe, C/C++ FFI |\n| CWE-78 | OS Command Injection | Python (subprocess), shell scripts |\n| CWE-416 | Use After Free | Rust unsafe, C/C++ |\n| CWE-862 | Missing Authorization | Web layer |\n| CWE-434 | Unrestricted File Upload | Web layer |\n| CWE-94 | Code Injection | Python (eval/exec), template engines |\n| CWE-20 | Improper Input Validation | All |\n| CWE-77 | Command Injection | All shell-out paths |\n| CWE-287 | Improper Authentication | Auth layer |\n| CWE-269 | Improper Privilege Management | Container, sudo |\n| CWE-502 | Deserialization of Untrusted Data | Python, Java |\n| CWE-200 | Exposure of Sensitive Information | Logs, errors, telemetry |\n| CWE-863 | Incorrect Authorization | Web layer |\n| CWE-918 | Server-Side Request Forgery | URL fetchers |\n| CWE-119 | Improper Restriction of Operations within Memory Buffer | Rust unsafe, C/C++ |\n| CWE-476 | NULL Pointer Dereference | Rust unsafe, C/C++ |\n| CWE-798 | Use of Hard-coded Credentials | All |\n| CWE-190 | Integer Overflow or Wraparound | All |\n| CWE-400 | Uncontrolled Resource Consumption | All |\n| CWE-306 | Missing Authentication for Critical Function | Web/API layer |\n\n## OWASP ASVS level targets\n\nFindings track the ASVS level they aim at:\n\n| Level | Target | Skill default |\n|-------|--------|---------------|\n| L1 | Opportunistic attacker | always |\n| L2 | Targeted attacker | when secrets-bearing config detected |\n| L3 | Determined attacker | only on `--focus all` with `--strict` |\n\n## RustSec advisory database\n\nFor Rust findings, cite the specific advisory ID\n(RUSTSEC-YYYY-NNNN). The `cargo audit` JSON output contains\nthese directly. Use them in the proposal's reversal plan to\nexplain *why* the upgrade is required.\n\n## How findings cite\n\nEach finding's `Citation:` line names:\n\n1. Primary CWE (always)\n2. NIST SSDF practice (always; pick the closest match)\n3. Optional: OWASP ASVS section, RustSec ID, PEP number, CVE\n\nExample:\n\n```\nCitation: CWE-502 (Deserialization of Untrusted Data),\nNIST SSDF PW.7 (Review and analyze human-readable code),\nOWASP ASVS V5.5 (Deserialization Prevention).\n```\n\nA finding with no primary CWE cannot be classified above\nADVISORY severity.\n\nFile v1.9.16:modules/proposal-shape.md\n\n# Proposal Shape\n\nEvery proposed remediation in a hardening report follows this\nschema. The schema is not optional: a finding without a complete\nproposal cannot be applied (the user can still choose to file or\ndefer it).\n\n## Required fields\n\n| Field | Purpose |\n|-------|---------|\n| `id` | Stable identifier across runs (e.g., `H7`, `PY03`) |\n| `severity` | CRITICAL / HIGH / MEDIUM / LOW / ADVISORY |\n| `citation` | Primary CWE plus NIST SSDF practice (mandatory) |\n| `file` | Single file the proposal touches (multi-file proposals split into siblings) |\n| `lines` | Affected line range, e.g., `42-58` |\n| `detection_signal` | What pattern the scanner saw (in safe-to-quote form) |\n| `proposal` | One-paragraph description of the fix |\n| `diff` | Concrete diff or config snippet, not \"consider doing X\" |\n| `blast_radius` | low / medium / high — see below |\n| `reversal_plan` | Exact command to revert and the conditions to reapply |\n| `expected_test` | Test path that should pass after the change |\n\n## Severity to default disposition\n\n| Severity | Default disposition |\n|----------|---------------------|\n| CRITICAL | apply or file immediately; never advisory |\n| HIGH | propose for apply with prompt |\n| MEDIUM | propose for apply only when `--auto-apply medium` |\n| LOW | file as issue by default |\n| ADVISORY | report only; never proposed |\n\nCRITICAL findings always prompt even under `--auto-apply`.\n\n## Blast radius scale\n\nThe proposal queries `Skill(pensive:blast-radius)` for the\nchange-impact graph and reports one of:\n\n| Tier | Definition |\n|------|------------|\n| **low** | Single file; no public API change; no signature change; no behavior visible to callers |\n| **medium** | Multiple files OR public API addition (new param with default, new method) OR test-only behavior change |\n| **high** | Public API breaking change OR cross-plugin coupling OR config schema change |\n\nHigh-blast-radius proposals require explicit approval even\nunder `--auto-apply`. The skill warns when the radius rises\nabove the user's current `--auto-apply` ceiling.\n\n## Reversal plan template\n\n```\nReversal:\n  command: git revert <sha> --no-edit\n  retry condition: <when it would be safe to reapply>\n  evidence file: reviews/harden-<date>.md (this report)\n```\n\nFor config changes that cannot be reverted by `git revert`\nalone (e.g., a CI permission change that runs only on push):\n\n```\nReversal:\n  command: git revert <sha> --no-edit\n  follow-up: re-trigger the workflow on master to confirm the\n             permissions are restored\n  evidence file: reviews/harden-<date>.md\n```\n\n## Expected-passing test\n\nEach proposal cites a test that should pass after the change:\n\n- If a test already exists, name it: `tests/unit/x.py::test_y`.\n- If a test must be added, the proposal includes the test code in\n  the same diff block. The test must fail against the\n  pre-proposal code (RED) and pass after (GREEN).\n\nA proposal without an expected test is downgraded to ADVISORY.\nThis is the harden equivalent of `Skill(imbue:proof-of-work)`'s\nIron Law.\n\n## Approval options (per finding)\n\nWhen the approval gate fires, the user gets:\n\n1. **apply** — apply the diff, commit, run gates, advance.\n2. **file** — create a GitHub issue with the proposal body and\n   close out the finding.\n3. **defer** — log to `.harden/backlog.md` for future runs to\n   surface again.\n4. **reject** — record a rejection with optional rationale; the\n   finding will not surface again unless code changes invalidate\n   the rejection.\n\nThe auto-apply ceiling determines which severities skip the gate\nentirely:\n\n```bash\n/harden --auto-apply low      # apply LOW automatically\n/harden --auto-apply medium   # apply LOW + MEDIUM automatically\n/harden --auto-apply high     # apply LOW + MEDIUM + HIGH automatically\n```\n\nCRITICAL is never auto-applied.\n\n## Worked example\n\n```yaml\nid: PY01\nseverity: HIGH\ncitation: \"CWE-502 (Deserialization of Untrusted Data), NIST SSDF PW.7\"\nfile: src/api/loader.py\nlines: 42-44\ndetection_signal: |\n  Module imports the Python stdlib unsafe-deserialization helper\n  and calls its loads() helper on bytes that originate from the\n  request body (data flows from request.body through validate()\n  into loader.loads()).\nproposal: |\n  Replace the unsafe loader call with json.loads. The payload\n  shape is JSON-compatible per the API spec (verified by reading\n  the OpenAPI schema for /v1/upload). This eliminates the\n  arbitrary-code-execution attack path while preserving the\n  positive-path behavior.\ndiff: |\n  --- a/src/api/loader.py\n  +++ b/src/api/loader.py\n  @@ -42,3 +42,5 @@\n  -from <stdlib-unsafe-loader> import loads\n  +import json\n  -    obj = loads(payload)\n  +    obj = json.loads(payload)\nblast_radius: low\nreversal_plan:\n  command: \"git revert <sha> --no-edit\"\n  retry_condition: \"do not retry; the previous form was unsafe by design\"\n  evidence_file: \"reviews/harden-2026-05-10.md\"\nexpected_test: tests/unit/api/test_loader.py::test_round_trip_json\n```\n\n## Multi-file proposals\n\nWhen a hardening fix needs touches across multiple files (e.g.,\nadding a `Tier` `Literal` requires updates in classifiers, the\nDORAMetrics dataclass, and the tests), split into sibling\nproposals (PY01a, PY01b, PY01c) with a shared `parent_id`. The\napproval gate applies them as one unit, but each is its own\ncommit so reverts stay surgical.\n\n## What a proposal must NOT do\n\n- Modify generated code, vendored code, or `node_modules`.\n- Touch the changelog except to add a `### Security` bullet.\n- Bump dependency versions beyond the minimum required for the\n  fix (a separate proposal per dep upgrade).\n- Introduce a new dependency without an `imbue:proof-of-work`\n  evidence trail showing the dep was vetted.\n- Disable existing tests or assertions to make the fix easier.\n\nFile v1.9.16:modules/python-checks.md\n\n# Python Hardening Checks\n\nDetectors for Python codebases. Each row is a discrete check the\nskill runs; each carries a CWE citation for the report.\n\nThe detection-signal column uses placeholder syntax for patterns\nthat the project's pre-commit security hooks block writing\nliterally. The hooks exist for a reason: this doc describes the\nrules, but the regexes themselves live in code where the safety\nreview treats them as data, not source. If a future contributor\nneeds to inspect the literal patterns, see the corresponding\ndetector module under `plugins/pensive/skills/harden/detectors/`\n(future work; not part of the v1 skill).\n\n## Detection ruleset\n\n| ID | Check | CWE | NIST SSDF | Detection signal |\n|----|-------|-----|-----------|------------------|\n| PY01 | Unsafe deserialization (the stdlib `pickle` family, `marshal`, `shelve`) | CWE-502 | PW.5.1 | `<unsafe-loader>.loads(` on bytes you do not control |\n| PY02 | YAML loaded without a safe Loader | CWE-502 | PW.9 | `yaml.load(` without `Loader=SafeLoader` |\n| PY03 | Code injection via `eval`/`exec`/`compile(...,'exec')` | CWE-94 | PW.5.1 | `<eval-family>(` with a non-constant argument |\n| PY04 | Shell-command injection in a child-process call | CWE-78 | PW.5.1 | bandit B602 / B605: child-process helper invoked with the shell-mode flag and a formatted string |\n| PY05 | SQL injection via string formatting | CWE-89 | PW.5.1 | `cursor.execute(f\"...\")` or `% ` formatting in a query |\n| PY06 | Path traversal in user-supplied paths | CWE-22 | PW.5.1 | `open(user_input)` without `Path.resolve()` and `is_relative_to()` |\n| PY07 | Insecure RNG used for security purposes | CWE-330 | PW.5.1 | `import random` then a token/secret/key generated from it; should be `secrets` |\n| PY08 | TLS verification disabled | CWE-295 | PW.9 | `requests.*(verify=False)`, `ssl.CERT_NONE`, `disable_warnings(InsecureRequestWarning)` |\n| PY09 | Hardcoded credentials | CWE-798 | PW.5.1 | regex match for `api[_-]?key`, `secret`, `token`, `passwd` literals; AWS prefixes (`AKIA...`) |\n| PY10 | Subprocess invocation without timeout | CWE-400 | PW.5.1 | `<child-proc>.run/Popen` without `timeout=` |\n| PY11 | Tarfile extraction without member filter | CWE-22 | PW.9 | `tarfile.*extractall(` without `filter=` (PEP 706; default became safe in 3.12+) |\n| PY12 | XML XXE / billion-laughs | CWE-611, CWE-776 | PW.9 | `xml.etree.ElementTree.parse(` (use `defusedxml`) |\n| PY13 | Jinja autoescape off in HTML context | CWE-79 | PW.9 | `Environment(autoescape=False)` or `Markup(user_input)` |\n| PY14 | Logging secrets | CWE-532 | PW.5.1 | `logger.*(token)`, `logger.*(password)`, `logger.*(api_key)` |\n| PY15 | Bare `except:` swallowing errors in security paths | CWE-754 | PW.7 | `except:` or `except Exception: pass` in auth or crypto paths |\n| PY16 | Async TOCTOU (time-of-check / time-of-use) | CWE-367 | PW.5.1 | `await is_authorized(...)` then `await act(...)` without re-check |\n| PY17 | Untrusted format string | CWE-134 | PW.5.1 | `(user_input).format(`, f-string built from user input, `\"%\" % user` |\n| PY18 | Insecure temp file | CWE-377 | PW.5.1 | `tempfile.mktemp(` (use `mkstemp` or `NamedTemporaryFile`) |\n| PY19 | `assert` for runtime auth check | CWE-617 | PW.5.1 | `assert user.is_admin` (assert is stripped under `python -O`) |\n| PY20 | `requests` without timeout | CWE-400 | PW.5.1 | `requests.get/post(...)` without `timeout=` |\n| PY21 | HTTP request smuggling on outdated frameworks | CWE-444 | RV.1 | `gunicorn<22.0.0` (CVE-2024-1135), `aiohttp<3.9.2` (CVE-2024-23829) |\n| PY22 | Multipart resource exhaustion | CWE-400 | RV.1 | `python-multipart<0.0.18` (CVE-2024-47874); FastAPI route without `max_part_size` |\n| PY23 | Weak hashing for passwords or auth tokens | CWE-327, CWE-328 | PW.5.1 | `hashlib.md5`, `hashlib.sha1` reachable from password / session-token paths |\n| PY24 | Missing TLS 1.2 floor | CWE-326 | PW.9 | `ssl.PROTOCOL_TLSv1`, `PROTOCOL_SSLv23` without `minimum_version` |\n| PY25 | Index pinning missing for PyPI consumption | CWE-829 | PW.4 | no `[[tool.uv.index]]` in `pyproject.toml`; no `--index-url` constraint in `requirements.txt` |\n| PY26 | Hash-unpinned installs | CWE-494, NIST SI-7 | PW.4 | `requirements.txt` without `--hash=` lines; missing `uv.lock`/`poetry.lock` |\n| PY27 | PyPI release without PEP 740 attestation | NIST SSDF PS.2.1 | PS.2 | release workflow uses static API token instead of `pypa/gh-action-pypi-publish@release/v1` (Trusted Publishers) |\n\n## Library substitution table\n\nWhen a finding fires, the proposal usually swaps the offending\nlibrary or call. The substitution table:\n\n| Bad | Good | Why |\n|-----|------|-----|\n| the unsafe-deserialization stdlib family | `json` if data is JSON-shaped, otherwise `msgspec` / `pydantic` | safe-by-default deserialization |\n| `yaml.load(...)` | `yaml.safe_load(...)` (or `ruamel.yaml.YAML(typ='safe')`) | rejects arbitrary tag construction |\n| `eval`, `exec` | `ast.literal_eval` for constants; otherwise refactor to a typed parser | no code path executes user input |\n| `random.{choice,token_bytes,...}` for security | `secrets.token_bytes/urlsafe`, `secrets.choice` | CSPRNG-backed |\n| `xml.etree.ElementTree` on untrusted input | `defusedxml.ElementTree` | XXE / billion-laughs hardened |\n| `urllib.request.urlopen` | `requests` (`timeout=`, `verify=True`) or `httpx` (defaults are safer) | timeout-by-default |\n| `tempfile.mktemp` | `tempfile.NamedTemporaryFile(delete=False)` | atomic creation |\n| `assert is_authorized()` | explicit `if not is_authorized(): raise PermissionError(...)` | survives `python -O` |\n| `hashlib.md5/sha1` for passwords | `argon2-cffi`, `bcrypt`, or `passlib` | KDF with cost factor |\n| static API tokens for PyPI | PyPI Trusted Publishers and sigstore attestation (PEP 740) | revocable, log-traceable, no shared secret |\n\n## Static-analyzer integration\n\nRun the canonical Python security tools and treat their findings\nas first-class harden findings:\n\n```bash\n# Bandit ruleset (PyCQA-maintained AST scanner)\nuv run bandit -r src/ -f json -o /tmp/harden-bandit.json\n\n# pip-audit on the lockfile (PyPA + Trail of Bits, OSV-backed)\nuv run pip-audit --lockfile uv.lock --format json > /tmp/harden-pipaudit.json\n\n# osv-scanner reads pyproject + lockfiles + Cargo.lock\nosv-scanner --format json . > /tmp/harden-osv.json\n\n# semgrep with the security-audit ruleset\nsemgrep --config=p/python --json --output=/tmp/harden-semgrep.json\n```\n\nFindings from these tools convert to the harden schema by joining\non file:line and severity. A bandit B301 finding (the unsafe\ndeserialization rule) becomes the same finding shape as the\ninternal PY01 detector, so the report does not double-count.\n\n## Frontier Python concerns (2025-2026)\n\nLoaded from `frontier-checks.md` for full coverage. Brief list:\n\n- PEP 740 sigstore attestations on PyPI (verify before install);\n  see Trail of Bits' \"Attestations: a new generation of\n  signatures on PyPI\" (Nov 2024).\n- Tarfile member filter (PEP 706) — `tarfile.data_filter` default\n  in Python 3.12+; verify the codebase does not still pass\n  `filter=None`.\n- pyproject.toml `[[tool.uv.index]]` priority pinning to defeat\n  dependency confusion attacks.\n- LLM SDK prompt-injection patterns and MCP server hardening\n  (CWE-1426; OWASP LLM Top 10 #01, #02).\n- ASGI middleware request smuggling (CVE-2024-23829 class).\n- Sandboxing application code: WASM (Pyodide), gVisor, nsjail.\n- Slopsquatting / package hallucination (arXiv 2406.10279):\n  LLM-suggested non-existent packages later registered as\n  malware. Mitigation: lockfile and `--require-hashes` and human\n  review on every dep addition.\n\n## Output schema\n\nEach Python finding follows the schema in\n`modules/proposal-shape.md`. The detection-signal text uses safe\nplaceholders so the doc itself does not trip secret-scanners or\nthe project's security pre-commit hooks; the actual scanner emits\nthe literal pattern with file:line context in the report.\n\nFile v1.9.16:modules/rust-checks.md\n\n# Rust Hardening Checks\n\nDetectors for Rust codebases. The Rust ecosystem ships strong\ndefault safety; the harden skill verifies the discipline is\nactually applied and the supply chain is curated.\n\nFor a deep ownership/unsafe audit, the skill defers to\n`Skill(pensive:rust-review)`. This module focuses on the\nhardening posture (capability use, supply-chain hygiene,\nside-channel defense) and frontier 2025-2026 practices.\n\n## Detection ruleset\n\n| ID | Check | CWE / RustSec | NIST SSDF | Detection signal |\n|----|-------|---------------|-----------|------------------|\n| RS01 | Crate root lacks `#![forbid(unsafe_code)]` and does not declare audited unsafe | CWE-119 | PW.5 | `lib.rs`/`main.rs` without forbid; no `audit/unsafe.md` |\n| RS02 | Unsafe block without `// SAFETY:` comment | CWE-119 | PW.7 | `unsafe {` not preceded by `// SAFETY:` line |\n| RS03 | `unwrap()` / `expect()` on caller-supplied data | CWE-754 | PW.5 | `.unwrap()` after `parse()`, `from_str`, `serde::from_*` on external input |\n| RS04 | `panic!` reachable from request handler | CWE-754 | PW.5 | `panic!`, `unimplemented!`, `unreachable!` on user-input branches |\n| RS05 | `cargo audit` not wired to CI | RV.1 | RV.1 | no `cargo audit` step in `.github/workflows/*.yml` |\n| RS06 | `cargo deny` config missing or not enforced | RV.1 | PW.4 | no `deny.toml` or CI step missing |\n| RS07 | `cargo vet` audits stale / missing for new deps | RV.2 | PW.4 | `supply-chain/audits.toml` does not cover new entries in `Cargo.lock` |\n| RS08 | Comparing secrets with `==` | CWE-208 | PW.5 | `==` between `&[u8]` typed as token/secret/digest; should be `subtle::ConstantTimeEq` |\n| RS09 | Secrets not zeroized on drop | CWE-316 | PW.5 | secret-typed struct without `Zeroize`/`ZeroizeOnDrop` |\n| RS10 | Async cancellation un-safe | CWE-362 | PW.5 | `tokio::select!` arms with non-cancel-safe futures (e.g., `BufReader::read_to_end`) |\n| RS11 | `Mutex::lock().unwrap()` in hot path | CWE-754 | PW.5 | poisoned-lock unwrap reachable from public API |\n| RS12 | Source replacement to private registry without integrity pin | CWE-494 | PW.4 | `[source.crates-io]` `replace-with` without checksum |\n| RS13 | Git dependency without `rev=` | CWE-494 | PW.4 | `git = \"...\"` without `rev = \"...\"` (mutable target) |\n| RS14 | Build script (`build.rs`) reads files outside `OUT_DIR` | CWE-829 | PW.6 | `build.rs` opens path containing `..` |\n| RS15 | `serde(deny_unknown_fields)` missing on auth-bearing structs | CWE-1287 | PW.5 | struct deriving `Deserialize` for an auth/config payload without `#[serde(deny_unknown_fields)]` |\n| RS16 | Compiler hardening flags absent | CWE-1244 | PW.6 | `.cargo/config.toml` missing `RUSTFLAGS` for stack protection / CFI |\n| RS17 | `unsafe impl Send/Sync` without proof | CWE-362 | PW.7 | `unsafe impl (Send|Sync) for ...` without SAFETY comment |\n| RS18 | FFI without bounds annotation | CWE-787 | PW.5 | `extern \"C\"` function with `*const T` / `*mut T` arg with no length param |\n\n## Tooling integration\n\n```bash\n# Vulnerability scan against RustSec advisory DB\ncargo audit --json > /tmp/harden-cargo-audit.json\n\n# Policy enforcement (license, advisory, source, ban list)\ncargo deny check --format json 2>/tmp/harden-deny.json\n\n# Cryptographic-supply-chain audit\ncargo vet check 2>&1 | tee /tmp/harden-vet.log\n\n# Unsafe block inventory (third-party tool; requires install)\ncargo geiger --output-format json > /tmp/harden-geiger.json\n\n# Mutation testing (high-leverage; expensive)\ncargo mutants --in-diff origin/main..HEAD --no-times --json\n```\n\nThe harden report joins these on file:line and advisory ID.\n\n## Capability-style hardening (frontier 2025-2026)\n\n| From | To | Why |\n|------|-----|-----|\n| `std::fs` ambient access | `cap-std::fs::Dir` capability | filesystem ops require an explicit handle, not a path |\n| raw `socket`/`std::net` | `cap-std::net` | network endpoints are capabilities, not strings |\n| environment-driven config | `secrecy::SecretString` for secrets | wrapper prevents `Debug`/`Display` leaks |\n| ad-hoc retry loops | `tower::retry` with backoff and budget | bounded resource consumption (CWE-400) |\n\nThese are recommendations, not blocking findings — surface in\nthe report as MEDIUM advisories with the rationale in the\nproposal.\n\n## Concurrency hardening\n\n| Pattern | Replace with | Reason |\n|---------|--------------|--------|\n| naked `std::sync::Mutex` in hot path | `parking_lot::Mutex` (no poisoning, smaller, faster) | reduces unwrap-on-poison footguns |\n| ad-hoc `Arc<Mutex<HashMap>>` | `dashmap::DashMap` | lock-free reads, sharded writes |\n| `tokio::sync::Mutex` held across `await` | `parking_lot::Mutex` for short critical sections | avoid tokio scheduler stalls |\n| `loom`-untested concurrent code | wire `cargo test --features loom` for lock-free types | model-checks all interleavings |\n\n## Compiler hardening flags\n\nIn `.cargo/config.toml`:\n\n```toml\n[target.'cfg(all())']\nrustflags = [\n    # Stack-smashing protection\n    \"-C\", \"force-frame-pointers=yes\",\n    # Disable sources of UB\n    \"-D\", \"warnings\",\n    # Treat unsafe-op-without-unsafe-fn as error in 2024 edition\n    \"-D\", \"unsafe_op_in_unsafe_fn\",\n]\n```\n\nFor sanitizer-instrumented test runs:\n\n```bash\nRUSTFLAGS=\"-Z sanitizer=address\" cargo +nightly test --target x86_64-unknown-linux-gnu\n```\n\n## Output schema\n\nSame as `python-checks.md`. Each Rust finding emits a single\nproposal with diff, blast radius, reversal plan, and expected\ntest. RustSec IDs go in the citation column when applicable.\n\nFile v1.9.16:skill-card.md\n\n## Description: <br>\nApplies NIST/CWE security hardening to Python and Rust code. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[athola](https://clawhub.ai/user/athola) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and security engineers use this skill to audit repositories for Python, Rust, supply-chain, CI/CD, container, and frontier security hardening gaps. It produces citation-backed findings and concrete remediation proposals for user approval, filing, deferral, or rejection. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: Broad security-hardening audits may trigger from generic Python, Rust, or security language and produce noisy findings. <br>\nMitigation: Review findings and proposals before acting, and use the report-only and approval-gate workflow to decide whether to apply, file, defer, or reject each item. <br>\nRisk: Approved fixes can modify source code, CI configuration, dependency policy, or container settings. <br>\nMitigation: Apply changes as discrete, reviewable units, rerun project gates after each change, and revert any change that fails validation. <br>\n\n\n## Reference(s): <br>\n- [ClawHub Skill Page](https://clawhub.ai/athola/skills/nm-pensive-harden) <br>\n- [Source Homepage](https://github.com/athola/claude-night-market/tree/master/plugins/pensive) <br>\n- [NIST and CWE Citation Backbone](modules/nist-controls.md) <br>\n- [Python Hardening Checks](modules/python-checks.md) <br>\n- [Rust Hardening Checks](modules/rust-checks.md) <br>\n- [Cross-Cutting Hardening Checks](modules/cross-cutting.md) <br>\n- [Frontier Hardening Checks](modules/frontier-checks.md) <br>\n- [Proposal Shape](modules/proposal-shape.md) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, markdown, code, shell commands, configuration, guidance] <br>\n**Output Format:** [Markdown reports with findings tables, remediation proposals, diff snippets, shell commands, and configuration snippets.] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [First run is report-only; applying remediations requires user approval or an explicit auto-apply flag.] <br>\n\n## Skill Version(s): <br>\n1.9.16 (source: ClawHub release evidence; artifact frontmatter says 1.9.8) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v1.9.14: 9 files, 23394 bytes\n\nFiles: modules/cross-cutting.md (5415b), modules/frontier-checks.md (5056b), modules/nist-controls.md (4262b), modules/proposal-shape.md (5761b), modules/python-checks.md (7917b), modules/rust-checks.md (5491b), skill-card.md (2646b), SKILL.md (10269b), _meta.json (137b)\n\nFile v1.9.14:SKILL.md\n\n---\nname: harden\ndescription: Applies NIST/CWE security hardening to Python and Rust code\nversion: 1.9.8\ntriggers:\n  - security\n  - hardening\n  - nist\n  - supply-chain\n  -\n\nArchive v1.9.13: 9 files, 23552 bytes\n\nFiles: modules/cross-cutting.md (5415b), modules/frontier-checks.md (5056b), modules/nist-controls.md (4262b), modules/proposal-shape.md (5761b), modules/python-checks.md (7917b), modules/rust-checks.md (5491b), skill-card.md (3164b), SKILL.md (10269b), _meta.json (137b)\n\nArchive v1.9.12: 9 files, 23297 bytes\n\nFiles: modules/cross-cutting.md (5415b), modules/frontier-checks.md (5056b), modules/nist-controls.md (4262b), modules/proposal-shape.md (5761b), modules/python-checks.md (7917b), modules/rust-checks.md (5491b), skill-card.md (2418b), SKILL.md (10269b), _meta.json (137b)\n\nArchive v1.0.0: 9 files, 23404 bytes\n\nFiles: modules/cross-cutting.md (5415b), modules/frontier-checks.md (5056b), modules/nist-controls.md (4262b), modules/proposal-shape.md (5761b), modules/python-checks.md (7917b), modules/rust-checks.md (5491b), skill-card.md (2812b), SKILL.md (10269b), _meta.json (136b)","readmeExcerpt":"Skill: harden Owner: athola Summary: Applies NIST/CWE security hardening to Python and Rust code Tags: latest:1.9.19 Version history: v1.9.19 | 2026-08-26T13:18:46.218Z | user Release v1.9.19 v1.9.17 | 2026-07-30T05:39:00.969Z | user Release v1.9.17 v1.9.16 | 2026-07-14T19:55:43.255Z | user Release v1.9.16 v1.9.14 | 2026-06-30T18:04:05.262Z | user Release v1.9.14 v1.9.13 | 2026-06-27T16:22:07.173Z | user Release v1.9","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"# Languages and build files\nfind . -type f \\( -name '*.py' -o -name '*.rs' -o -name '*.sh' \\) \\\n  | head -200 > /tmp/harden-langs.txt\n\n# Build manifests\nls pyproject.toml Cargo.toml package.json go.mod 2>/dev/null\n\n# CI workflows and pre-commit\nls .github/workflows/ .pre-commit-config.yaml 2>/dev/null\n\n# Hooks and Dockerfiles\nfind . -path ./node_modules -prune -o -type f \\\n  \\( -name 'hooks.json' -o -name 'Dockerfile*' \\) -print"},{"language":"bash","snippet":"git add <touched files>\ngit commit -m \"harden: <finding-id> <one-line summary>\""},{"language":"bash","snippet":"make test --quiet && make lint && make type-check"},{"language":"markdown","snippet":"# Hardening Report — <date>\n\n## Executive Summary\n\n- Codebase: <repo> @ <sha>\n- Languages scanned: Python (X files), Rust (Y files)\n- NIST SSDF practices covered: PW.4, PW.7, PW.8, RV.1, RV.2\n- CWE Top 25 hits: <count> across <distinct CWEs>\n- Disposition: <N> applied, <N> filed, <N> deferred, <N> rejected\n\n## Findings\n\n| ID | Severity | Citation | File:Line | Disposition |\n|----|----------|----------|-----------|-------------|\n| H1 | CRITICAL | CWE-502, NIST SSDF PW.7 | `src/x.py:45` | applied (commit abc123) |\n| H2 | HIGH | CWE-89, NIST SSDF PW.4 | `src/y.py:120` | filed (#456) |\n\n## Per-finding detail\n\n### H1 — Unsafe deserialization\n\n**Citation:** CWE-502 (Deserialization of Untrusted Data),\nNIST SSDF PW.7 (Review and analyze human-readable code).\n\n**Detection signal:**\n- File: `src/x.py:45`\n- Pattern: <module>.loads(user_supplied_input)\n- Reachability: untrusted, comes from request body\n\n**Proposal:** ...\n\n**Blast radius:** ...\n\n**Reversal plan:** ..."},{"language":"bash","snippet":"# CycloneDX SBOM for the whole repo\nsyft . -o cyclonedx-json > sbom.cdx.json\n\n# SPDX SBOM (alternative format)\nsyft . -o spdx-json > sbom.spdx.json\n\n# Verify against the in-toto attestation if released\ncosign verify-attestation --type slsaprovenance \\\n  --certificate-identity-regexp '.*' --certificate-oidc-issuer-regexp '.*' \\\n  ghcr.io/<org>/<image>:<tag>"},{"language":"yaml","snippet":"repos:\n  - repo: https://github.com/PyCQA/bandit\n    rev: 1.7.10\n    hooks:\n      - id: bandit\n        args: [\"-c\", \"pyproject.toml\"]\n        additional_dependencies: [\"bandit[toml]\"]\n  - repo: https://github.com/gitleaks/gitleaks\n    rev: v8.21.2\n    hooks:\n      - id: gitleaks\n  - repo: https://github.com/Yelp/detect-secrets\n    rev: v1.5.0\n    hooks:\n      - id: detect-secrets\n        args: [\"--baseline\", \".secrets.baseline\"]"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: harden\ndescription: Applies NIST/CWE security hardening to Python and Rust code\nversion: 1.9.8\ntriggers:\n  - security\n  - hardening\n  - nist\n  - supply-chain\n  - python\n  - rust\n  - cwe\n  - auditing code for vulnerabilities or proposing concrete security remediations\nmetadata: {\"openclaw\": {\"homepage\": \"https://github.com/athola/claude-night-market/tree/master/plugins/pensive\", \"emoji\": \"\\ud83d\\udd12\", \"requires\": {\"config\": [\"night-market.pensive:safety-critical-patterns\", \"night-market.pensive:rust-review\", \"night-market.pensive:bug-review\", \"night-market.pensive:tiered-audit\", \"night-market.pensive:blast-radius\", \"night-market.leyline:supply-chain-advisory\", \"night-market.leyline:authentication-patterns\", \"night-market.leyline:content-sanitization\", \"night-market.abstract:hook-authoring\", \"night-market.imbue:proof-of-work\"]}}}\nsource: claude-night-market\nsource_plugin: pensive\n---\n\n> **Night Market Skill** — ported from [claude-night-market/pensive](https://github.com/athola/claude-night-market/tree/master/plugins/pensive). For the full experience with agents, hooks, and commands, install the Claude Code plugin.\n\n\n# Harden Codebase Skill\n\nActive security hardening — scan the existing repository for\nvulnerabilities and forward-facing threats, then propose concrete\nremediations the user can approve, defer, or file.\n\nThis skill is the engine behind `/harden`. It complements the\nClaude Code built-in `/security-review` (which scans the pending\ndiff) by sweeping the whole repository against citation-backed\nchecks rather than line-level review of in-flight code.\n\n## When To Use\n\n- Quarterly security-posture audits.\n- Before tagging a release that touches sensitive code paths.\n- After a published advisory affects the language ecosystem.\n- When onboarding a new repository and want a baseline.\n- After integrating a new dependency or upstream service.\n\n## When NOT To Use\n\n- Pending-diff review on a single PR. Use `/security-review`.\n- Architecture-level threat modeling. Use `attune:war-room`\n  with a security-focused panel.\n- Cryptographic protocol review. The skill flags suspect crypto\n  but does not propose protocol fixes (specialist work).\n- One-off bug hunting. Use `pensive:bug-review`.\n\n## Required TodoWrite Items\n\n1. `harden:discovery` — inventory languages, build files, hooks,\n   CI workflows\n2. `harden:scan-python` — run python-checks.md detectors when\n   Python is present\n3. `harden:scan-rust` — run rust-checks.md detectors when Rust\n   is present\n4. `harden:scan-cross-cutting` — run cross-cutting.md detectors\n   (deps, secrets, SBOM, CI)\n5. `harden:scan-frontier` — run frontier-checks.md (PQC, LLM\n   supply chain, sandboxing)\n6. `harden:nist-mapping` — map findings to NIST SSDF practices\n7. `harden:proposals` — for each finding above the threshold,\n   draft a concrete remediation per `modules/proposal-shape.md`\n8. `harden:approval-gate` — present proposals to the user for\n   apply / file / defer / reject\n9. `harden:apply-and-validate`"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7d107jg9jv602h9ytsegydq184a42s\",\n  \"slug\": \"nm-pensive-harden\",\n  \"version\": \"1.9.19\",\n  \"publishedAt\": 1787750326218\n}"},{"path":"modules/cross-cutting.md","content":"# Cross-Cutting Hardening Checks\n\nChecks that apply regardless of the source language: dependency\nposture, secret hygiene, CI/CD chain, container shape, and the\nSBOM.\n\n## Dependency posture (composes leyline:supply-chain-advisory)\n\n| ID | Check | CWE / NIST | Detection |\n|----|-------|------------|-----------|\n| DEP01 | Lockfile committed | PW.4 | absence of `uv.lock` / `Cargo.lock` / `package-lock.json` |\n| DEP02 | Dependency scanner runs in CI | RV.1 | no `pip-audit`/`cargo audit`/`npm audit` step in workflows |\n| DEP03 | Known-bad versions blocked | CWE-829 | `leyline:supply-chain-advisory` blocklist not consulted |\n| DEP04 | Auto-update bot configured | RV.1 | no `dependabot.yml` / `renovate.json` |\n| DEP05 | Direct deps pinned to exact versions | CWE-494 | `^1.2` / `~1.2` / `1.2.*` for security-critical deps |\n| DEP06 | Hash-pinned for top-tier supply-chain trust | CWE-494 | `--require-hashes` not used in `pip` / `requirements.txt` |\n| DEP07 | License policy enforced | none | no `cargo deny` license rules / no `pip-licenses` check |\n\n## Secret hygiene\n\n| ID | Check | CWE | Detection |\n|----|-------|-----|-----------|\n| SEC01 | Pre-commit secret scanner installed | CWE-798 | no `gitleaks` / `trufflehog` / `talisman` in `.pre-commit-config.yaml` |\n| SEC02 | `.env` files git-ignored | CWE-200 | `.env` tracked or unmatched in `.gitignore` |\n| SEC03 | Long-lived secrets in CI | CWE-798 | `secrets.SOME_KEY` used without `if: github.event_name != 'pull_request'` |\n| SEC04 | OIDC publishing configured | CWE-798 | PyPI/Cargo publish step uses `password:` rather than OIDC `id-token: write` |\n| SEC05 | Audit trail for secret access | PW.7 | repo settings: secret-access logs not retained |\n| SEC06 | Sealed-secrets / secret manager | CWE-798 | secrets baked into config files instead of fetched from a manager |\n\n## CI/CD chain (GitHub Actions example)\n\n| ID | Check | NIST SSDF | Detection |\n|----|-------|-----------|-----------|\n| CI01 | Third-party actions pinned by SHA, not tag | PW.4 | `uses: foo/bar@v1` instead of `@<full SHA>` |\n| CI02 | `permissions:` block per workflow | PW.4 | top-level `permissions:` missing or `permissions: write-all` |\n| CI03 | `GITHUB_TOKEN` minimum scope | PW.4 | default permissions used when `contents: read` would suffice |\n| CI04 | Concurrency cancel for stale runs | RV.2 | no `concurrency.cancel-in-progress: true` |\n| CI05 | Workflow dispatch requires approval for protected branches | PW.4 | branch protection allows direct dispatch |\n| CI06 | SLSA provenance generated for releases | RV.2 | release workflow does not invoke `slsa-framework/slsa-github-generator` |\n| CI07 | SBOM generated and attached to releases | RV.2 | release workflow lacks `cyclonedx`/`syft`/`spdx-sbom-generator` step |\n\n## Container hardening (when Dockerfiles exist)\n\n| ID | Check | CWE | Detection |\n|----|-------|-----|-----------|\n| CO01 | Non-root `USER` set | CWE-269 | `USER root` or `USER` directive missing |\n| CO02 | `FROM` is digest-pinned | CWE-"},{"path":"modules/frontier-checks.md","content":"# Frontier Hardening Checks (2025-2026)\n\nForward-facing checks that defend against threats just emerging\nin production. Findings here are usually MEDIUM by default\nbecause exploitation is non-trivial; promote to HIGH when the\ncodebase has a high-value attack surface (auth provider, signing\nservice, data plane).\n\n## Post-quantum migration readiness\n\nThe NSA CNSA 2.0 timeline targets quantum-resistant crypto for\nNSS by 2030; PCI DSS 4.0.1 expects an inventory by 2026. Most\napplication code is not the right place to swap algorithms, but\nthe *crypto-agility* posture is.\n\n| ID | Check | Citation | Detection |\n|----|-------|----------|-----------|\n| PQ01 | Signing/verification has a single hard-coded algorithm | NIST IR 8547 | `algorithms = [\"RS256\"]` or `algorithms = [\"EdDSA\"]` literal in JWT/JWS code |\n| PQ02 | Algorithm selection driven by config, not code | NIST IR 8547 | move the algorithm list behind a `signing_algorithms` config field |\n| PQ03 | Inventory of crypto APIs in the repo | NIST CNSA 2.0 | no `docs/crypto-inventory.md` or equivalent |\n| PQ04 | TLS clients accept algorithm downgrade silently | CWE-757 | `requests` / `reqwest` defaults without minimum-TLS pin |\n\nThe proposal for PQ02 is usually a small refactor: move\n`algorithms = [\"EdDSA\"]` into a config table the operator can\noverride. The skill does not propose ML-DSA / Falcon migration\nin application code (still specialist work).\n\n## LLM and agentic supply chain\n\nA new failure mode in 2025: AI assistants suggest dependencies\nthat look plausible but do not exist (or are typosquats). The\nchecks below defend the development pipeline itself.\n\n| ID | Check | Citation | Detection |\n|----|-------|----------|-----------|\n| LLM01 | Index pinning to defeat dependency confusion | OWASP LLM Top 10 #08 | `pyproject.toml` lacks `[[tool.uv.index]]` priority order |\n| LLM02 | New deps require human review | OWASP LLM Top 10 #08 | no CI rule blocking auto-merge on dep PRs |\n| LLM03 | LLM SDK calls validate role/instruction boundaries | OWASP LLM Top 10 #01 | system prompt concatenated with user input without separator/role |\n| LLM04 | Tool-use response sanitization | OWASP LLM Top 10 #02 | tool output rendered to UI/terminal without escape |\n| LLM05 | MCP server allowlist of tools | OWASP LLM Top 10 #02 | MCP config mounts every tool from a server (no allowlist) |\n| LLM06 | Agent action audit trail | OWASP LLM Top 10 #06 | no log of tool invocations with inputs |\n\n## Sandbox / isolation posture\n\nFor codebases that execute user-supplied or AI-supplied code:\n\n| ID | Check | Why | Today's option |\n|----|-------|-----|----------------|\n| SB01 | User code runs in same process as host | host privilege escalation | Pyodide WASM (Python), wasmtime (Rust) |\n| SB02 | Network egress unrestricted from sandbox | data exfiltration | gVisor egress policy, NetworkPolicy in K8s |\n| SB03 | Filesystem capabilities ambient | path-based attacks | `cap-std` (Rust), bind-mount only required dirs |\n| SB04 | Resource limits "},{"path":"modules/nist-controls.md","content":"# NIST and CWE Citation Backbone\n\nEvery finding in a hardening report carries a citation. This\nmodule is the lookup table.\n\n## NIST SSDF (SP 800-218) practice mapping\n\nThe Secure Software Development Framework defines four practice\ngroups: Prepare the Organization (PO), Protect Software (PS),\nProduce Well-Secured Software (PW), Respond to Vulnerabilities\n(RV). Findings map to PW and RV most often.\n\n| Practice | What it requires | Detector signal |\n|----------|------------------|-----------------|\n| PW.4 | Reuse existing well-secured software | dependencies pinned, scanned, attested |\n| PW.5 | Create source code aligned with secure practices | linter enforces auth/crypto/serialization rules |\n| PW.6 | Configure compilation, build processes, links | RUSTFLAGS hardening, Python `-W error`, reproducible builds |\n| PW.7 | Review and analyze human-readable code | SAST run in CI; findings tracked |\n| PW.8 | Test executable code | fuzz coverage, mutation tests, property tests |\n| PW.9 | Configure software with secure default settings | yaml SafeLoader, TLS verify on, autoescape on |\n| RV.1 | Identify, confirm vulnerabilities on a continuous basis | dependency scanner runs on every push |\n| RV.2 | Assess, prioritize, remediate vulnerabilities | severity policy, SLA per severity |\n| RV.3 | Analyze vulnerabilities to identify root causes | post-incident notes feed PW.4-9 |\n\nThe skill's executive summary lists each practice and whether the\ncodebase has at least one detector firing for it. Coverage <80%\nof PW.4-PW.9 is itself a finding (RV.1 unmet).\n\n## CWE Top 25 (2024) mapping\n\nThe skill prioritizes detectors that map to the CWE Top 25 most\ndangerous software weaknesses. Per-finding citations name the\nspecific CWE, not just \"Top 25.\"\n\n| CWE | Title | Languages most often hit |\n|-----|-------|--------------------------|\n| CWE-79 | Cross-site Scripting | Python, JS |\n| CWE-787 | Out-of-bounds Write | Rust unsafe, C/C++ FFI |\n| CWE-89 | SQL Injection | Python, Rust |\n| CWE-352 | CSRF | Python web frameworks |\n| CWE-22 | Path Traversal | All |\n| CWE-125 | Out-of-bounds Read | Rust unsafe, C/C++ FFI |\n| CWE-78 | OS Command Injection | Python (subprocess), shell scripts |\n| CWE-416 | Use After Free | Rust unsafe, C/C++ |\n| CWE-862 | Missing Authorization | Web layer |\n| CWE-434 | Unrestricted File Upload | Web layer |\n| CWE-94 | Code Injection | Python (eval/exec), template engines |\n| CWE-20 | Improper Input Validation | All |\n| CWE-77 | Command Injection | All shell-out paths |\n| CWE-287 | Improper Authentication | Auth layer |\n| CWE-269 | Improper Privilege Management | Container, sudo |\n| CWE-502 | Deserialization of Untrusted Data | Python, Java |\n| CWE-200 | Exposure of Sensitive Information | Logs, errors, telemetry |\n| CWE-863 | Incorrect Authorization | Web layer |\n| CWE-918 | Server-Side Request Forgery | URL fetchers |\n| CWE-119 | Improper Restriction of Operations within Memory Buffer | Rust unsafe, C/C++ |\n| CWE-476 | NULL Pointer Dereference | Rust "}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Applies NIST/CWE security hardening to Python and Rust code Skill: harden Owner: athola Summary: Applies NIST/CWE security hardening to Python and Rust code Tags: latest:1.9.19 Version history: v1.9.19 | 2026-08-26T13:18:46.218Z | user Release v1.9.19 v1.9.17 | 2026-07-30T05:39:00.969Z | user Release v1.9.17 v1.9.16 | 2026-07-14T19:55:43.255Z | user Release v1.9.16 v1.9.14 | 2026-06-30T18:04:05.262Z | user Release v1.9.14 v1.9.13 | 2026-06-27T16:22:07.173Z | user Release v1.9","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":2101,"uniquenessScore":52,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T16:09:39.775Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T16:09:39.775Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T21:00:28.138Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}