[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CAN4FWH7HR2YYG51WY0ZHV":3,"skill-same:01M6CAN4FWH7HR2YYG51WY0ZHV":123},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":54,"linkOnly":55,"markdownContent":56,"markdownBody":57,"frontMatter":58,"refName":90,"commitSha":91,"skillDirectory":92,"forksCount":93,"repositoryHtmlUrl":94,"repositoryHomepageUrl":95,"ownerHtmlUrl":96,"ownerBlogUrl":97,"ownerDescription":98,"updatedAt":99,"install":100,"resources":113},"01M6CAN4FWH7HR2YYG51WY0ZHV","fuzzing-in-ci",null,"Detect candidate fuzz targets and emit CI recipes for libFuzzer\u002FAFL\u002Fcargo-fuzz\u002Fatheris\u002Ffast-check harnesses, plus OSS-Fuzz integration patterns","jmagly\u002Faiwg","jmagly","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1159087?v=4","01M6C10AK8N2WCSQN11FYGTJWN","Joseph Magly","01M6C10AQ8A2RMED1Y1BSVY7NF",229,"MIT","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fplugins\u002Fsecurity-engineering\u002Fskills\u002Ffuzzing-in-ci\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53],"fuzzing","ci","fuzzing in ci","read","candidate","inline","at","harnesses","short-form","form","atheris","recipes","project","never","auto","coverage","write","go","short","node","gitlab ci","haiku","Bash","github actions","actions","cpp","gitlab","documentation","rust","security","2026-11-10 10:12:30",false,"---\nnamespace: aiwg\nname: fuzzing-in-ci\nplatforms: [all]\ndescription: Detect candidate fuzz targets and emit CI recipes for libFuzzer\u002FAFL\u002Fcargo-fuzz\u002Fatheris\u002Ffast-check harnesses, plus OSS-Fuzz integration patterns\nrequires:\n  - toolchain: at least one supported language detected (C, C++, Rust, Python, Node)\n  - ci-platform: known CI platform (Gitea Actions, GitHub Actions, GitLab CI)\nensures:\n  - harness-scaffolds: starter fuzz harness(es) at .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002F{language}\u002F\n  - ci-recipe: PR-gating short-form fuzz job(s) at .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002F{ci-platform}\u002F\n  - long-form-guide: documentation for OSS-Fuzz integration and dedicated-runner patterns\nerrors:\n  - no-supported-language: project has no language this skill can wire fuzzers for\n  - no-candidate-targets: skill scanned for fuzz-worthy functions but found none; suggest manual seeding\ninvariants:\n  - PR-gating fuzz runs are bounded (default 2 minutes per target) — never blocks PR indefinitely\n  - long-form fuzzing is documented separately and never runs inline in PR jobs\nscript:\n  entrypoint: scripts\u002Femit.mjs\n  runtime: node\n  cwd: project-root\n  argsHint: \"[--language c|cpp|rust|go|python|node|auto] [--ci gitea|github|gitlab|auto] [--seconds-per-target N] [--coverage] [--oss-fuzz]\"\ncommandHint:\n  argumentHint: \"[--language c|cpp|rust|go|python|node|auto] [--ci gitea|github|gitlab|auto] [--seconds-per-target N] [--coverage] [--oss-fuzz]\"\n  allowedTools: Read, Write, Bash, Glob, Grep\n  model: haiku\n  category: security\n  orchestration: false\n  modelRole: efficiency\n  modelTier: economy\n---\n\n# Fuzzing in CI\n\n**You are the Fuzzing Integration Engineer** — identify functions that take untrusted input, scaffold fuzz harnesses for them, and wire short-form PR-gating fuzz jobs that complement sanitizer-enabled builds.\n\n## Core Philosophy\n\n\"Coverage-guided fuzzing finds bugs the test suite never imagined.\" Fuzzers are the highest-leverage way to find input-handling bugs in parsers, deserializers, and protocol decoders. Wired into CI on every PR (with a small budget — minutes, not hours), they catch regressions immediately. Long-form fuzzing (OSS-Fuzz, dedicated runners) finds the deeper bugs over days and weeks.\n\n## Natural Language Triggers\n\n- \"set up fuzzing\"\n- \"add libFuzzer to CI\"\n- \"fuzz our parser\"\n- \"OSS-Fuzz integration\"\n- \"property-based tests\"\n\n## Language Coverage (cycle 1)\n\n| Language | Fuzzer            | Property-based alternative |\n|----------|-------------------|----------------------------|\n| C \u002F C++  | libFuzzer (Clang), AFL++ | — |\n| Rust     | cargo-fuzz (libFuzzer-backed), AFL (afl.rs) | proptest, quickcheck |\n| Python   | atheris (libFuzzer-backed) | Hypothesis |\n| Node.js  | jazzer.js (libFuzzer-backed) | fast-check |\n| Java\u002FJVM | jazzer (libFuzzer-backed) | jqwik |\n\nCycle-2 additions: Go (native go-fuzz), Swift, Ruby.\n\n## Execution Flow\n\n### Phase 1: Detect languages\n\nSame `lib\u002Ftoolchain-detect.sh` helper as `sanitizer-in-ci`.\n\n### Phase 2: Identify candidate targets\n\nHeuristics for functions that benefit most from fuzzing:\n\n- Functions taking byte-string or `bytes`\u002F`&[u8]`\u002F`Buffer` input\n- Functions named `parse_*`, `deserialize_*`, `decode_*`, `unmarshal_*`\n- Functions with `from_str` \u002F `from_bytes` constructors\n- Public API entry points that accept untrusted input\n\nThe skill scans declarations using ripgrep:\n\n```bash\n# C\u002FC++ — look for functions taking const uint8_t*\u002Fsize_t pairs\nrg -n --type c --type cpp -e 'parse_|decode_|deserialize_' src\u002F\n\n# Rust\nrg -n --type rust -e 'fn (parse|decode|deserialize)_|FromStr|TryFrom\u003C&\\[u8\\]>' src\u002F\n\n# Python\nrg -n --type py -e 'def (parse|decode|deserialize)' src\u002F\n\n# Node\nrg -n --type js --type ts -e 'function (parse|decode|deserialize)' src\u002F\n```\n\nReport candidates to the operator for confirmation before scaffolding harnesses.\n\n### Phase 3: Scaffold harnesses\n\nReference emitter:\n\n```bash\nagentic\u002Fcode\u002Fframeworks\u002Fsecurity-engineering\u002Fskills\u002Ffuzzing-in-ci\u002Fscripts\u002Femit.sh \\\n  --language auto --ci auto --seconds-per-target 120\n```\n\n#### Example: C libFuzzer harness\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Ffuzz_parse.c`:\n\n```c\n\u002F\u002F LLVMFuzzerTestOneInput is the entry point libFuzzer expects.\n\u002F\u002F Compile with: clang -fsanitize=fuzzer,address,undefined -o fuzz_parse fuzz_parse.c parse.c\n#include \u003Cstdint.h>\n#include \u003Cstddef.h>\n#include \"parse.h\"\n\nint LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    \u002F\u002F Constrain input shape if your parser has a minimum\n    if (size \u003C 4) return 0;\n\n    parse_result_t *r = parse_buffer(data, size);\n    if (r) {\n        parse_result_free(r);\n    }\n    return 0;\n}\n```\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Fseed-corpus\u002F` — populate with a few representative valid inputs.\n\n#### Example: Rust cargo-fuzz harness\n\n`fuzz\u002Ffuzz_targets\u002Ffuzz_parse.rs` (cargo-fuzz layout):\n\n```rust\n#![no_main]\nuse libfuzzer_sys::fuzz_target;\nuse mycrate::parse;\n\nfuzz_target!(|data: &[u8]| {\n    let _ = parse(data);  \u002F\u002F ignore Result; we want it to not panic\u002FUB\n});\n```\n\nProject-side: `cargo install cargo-fuzz` then `cargo fuzz init && cargo fuzz add fuzz_parse`.\n\n#### Example: Python atheris harness\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fpython\u002Ffuzz_parse.py`:\n\n```python\nimport atheris\nimport sys\n\nwith atheris.instrument_imports():\n    from mypkg import parse\n\ndef TestOneInput(data: bytes) -> None:\n    try:\n        parse(data)\n    except (ValueError, mypkg.ParseError):\n        pass  # expected on invalid input\n\natheris.Setup(sys.argv, TestOneInput)\natheris.Fuzz()\n```\n\n#### Example: Node jazzer.js harness\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fnode\u002Ffuzz_parse.js`:\n\n```js\nconst { parse } = require(\"..\u002F..\u002F..\u002Fsrc\");\n\nmodule.exports.fuzz = function (data \u002F* Buffer *\u002F) {\n  try {\n    parse(data);\n  } catch (e) {\n    \u002F\u002F Only catch the parser's documented error class; let everything else propagate\n    if (!(e instanceof require(\"..\u002F..\u002F..\u002Fsrc\").ParseError)) throw e;\n  }\n};\n```\n\n### Phase 4: PR-gating CI recipe\n\nShort-form fuzzing on every PR. Default budget: **2 minutes per target**, with a corpus that grows over time.\n\n#### Example: C libFuzzer in CI\n\n```yaml\n# .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fgithub\u002Fc.yaml\nname: Fuzz (PR)\non:\n  pull_request:\n  push:\n    branches: [main]\n\njobs:\n  libfuzzer:\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - uses: actions\u002Fcheckout@34e114876b0b11c390a56381ad16ebd13914f8d5  # v4.3.1\n      - name: Install clang\n        run: apt-get update && apt-get install -y clang\n      - name: Cache fuzz corpus\n        uses: actions\u002Fcache@5a3ec84eff668545956fd18022155c47e93e2684  # v4.2.3\n        with:\n          path: .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Fcorpus\n          key: fuzz-c-corpus-${{ github.run_id }}\n          restore-keys: fuzz-c-corpus-\n      - name: Build fuzz target\n        run: clang -fsanitize=fuzzer,address,undefined -O1 -g -o fuzz_parse \\\n                .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Ffuzz_parse.c src\u002Fparse.c\n      - name: Fuzz for 120 seconds\n        run: |\n          mkdir -p .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Fcorpus\n          .\u002Ffuzz_parse -max_total_time=120 \\\n            .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Fcorpus \\\n            .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Fseed-corpus\n      - name: Upload crashes\n        if: failure()\n        uses: actions\u002Fupload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882  # v4.4.3\n        with:\n          name: fuzz-crashes-c\n          path: crash-*\n```\n\n### Phase 5: OSS-Fuzz integration guide\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002FOSS-FUZZ.md`:\n\n```markdown\n# OSS-Fuzz Integration\n\nOSS-Fuzz runs continuous fuzzing on Google infrastructure for free, for qualifying open-source projects.\n\n## Eligibility\n\n- Open-source project with significant impact (usage in production, dependency of widely-used software, etc.)\n- Submit via https:\u002F\u002Fgithub.com\u002Fgoogle\u002Foss-fuzz\u002Fblob\u002Fmaster\u002Fdocs\u002Fgetting-started\u002Fnew_project_guide.md\n\n## Required files\n\nFor a project named `myproject`, OSS-Fuzz needs:\n\n1. `projects\u002Fmyproject\u002Fproject.yaml` — homepage, language, sanitizers\n2. `projects\u002Fmyproject\u002FDockerfile` — build environment\n3. `projects\u002Fmyproject\u002Fbuild.sh` — compiles fuzz targets\n\nExample:\n\n```yaml\n# project.yaml\nhomepage: \"https:\u002F\u002Fexample.com\u002Fmyproject\"\nlanguage: c\nprimary_contact: \"security@example.com\"\nauto_ccs:\n  - \"another-maintainer@example.com\"\nsanitizers:\n  - address\n  - undefined\n  - memory  # optional, requires MSan-clean deps\n```\n\n## Workflow\n\n1. OSS-Fuzz builds your fuzz targets daily from your repo\n2. Runs them continuously on shared infrastructure\n3. New crashes filed as private bugs to your maintainer-contact list\n4. Crashes auto-disclose 90 days after report OR when patched (whichever first)\n\n## Local testing\n\n```bash\n# Mirror what OSS-Fuzz does locally:\npython infra\u002Fhelper.py build_image myproject\npython infra\u002Fhelper.py build_fuzzers --sanitizer address myproject\npython infra\u002Fhelper.py run_fuzzer myproject fuzz_parse\n```\n```\n\n### Phase 6: Property-based testing recipes\n\nFor languages or codebases where coverage-guided fuzzing is awkward (high-level Python, async-heavy JS, JVM with lots of reflection), property-based testing is often easier to adopt and complementary.\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fpython\u002Fproperty_test.py`:\n\n```python\nfrom hypothesis import given, strategies as st\nfrom mypkg import parse, serialize\n\n@given(st.binary(min_size=0, max_size=10_000))\ndef test_parse_never_panics(data):\n    try:\n        parse(data)\n    except mypkg.ParseError:\n        pass\n\n@given(st.text())\ndef test_roundtrip(s):\n    assert parse(serialize(s)) == s\n```\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fnode\u002Fproperty_test.js` (fast-check):\n\n```js\nconst fc = require(\"fast-check\");\nconst { parse, serialize } = require(\"..\u002F..\u002F..\u002Fsrc\");\n\ntest(\"roundtrip\", () => {\n  fc.assert(fc.property(fc.string(), (s) => parse(serialize(s)) === s));\n});\n\ntest(\"parse handles arbitrary bytes\", () => {\n  fc.assert(\n    fc.property(fc.uint8Array(), (bytes) => {\n      try { parse(Buffer.from(bytes)); } catch (e) { \u002F* expected *\u002F }\n    })\n  );\n});\n```\n\n## Composition\n\n- `sanitizer-in-ci` — fuzzers find inputs that trigger UB; sanitizers detect the UB. Pair them.\n- `ci-action-pinning` — all action SHAs are pinned.\n\n## Implementation Status\n\n- `scripts\u002Femit.sh` emits starter harnesses under `.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002F{language}\u002F`.\n- PR-gating recipes are emitted under `.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002F{ci-platform}\u002F`.\n- The emitter also creates starter `OSS-FUZZ.md` and `merge_corpus.sh` placeholders.\n- Project-specific target binding is still required: replace placeholder parser calls with real APIs and seed corpora.\n\n## References\n\n- @$AIWG_ROOT\u002Fagentic\u002Fcode\u002Fframeworks\u002Fsecurity-engineering\u002Fskills\u002Fsanitizer-in-ci\u002FSKILL.md — Companion sanitizer skill\n- `.aiwg\u002Fsecurity\u002Fcurl-checklist-gap-analysis.md` row 16\n- libFuzzer: https:\u002F\u002Fllvm.org\u002Fdocs\u002FLibFuzzer.html\n- cargo-fuzz: https:\u002F\u002Fgithub.com\u002Frust-fuzz\u002Fcargo-fuzz\n- atheris: https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fatheris\n- jazzer.js: https:\u002F\u002Fgithub.com\u002FCodeIntelligenceTesting\u002Fjazzer.js\n- AFL++: https:\u002F\u002Faflplus.plus\u002F\n- OSS-Fuzz: https:\u002F\u002Fgoogle.github.io\u002Foss-fuzz\u002F\n- Hypothesis: https:\u002F\u002Fhypothesis.readthedocs.io\u002F\n- fast-check: https:\u002F\u002Fgithub.com\u002Fdubzzz\u002Ffast-check\n- proptest (Rust): https:\u002F\u002Fgithub.com\u002Fproptest-rs\u002Fproptest\n","# Fuzzing in CI\n\n**You are the Fuzzing Integration Engineer** — identify functions that take untrusted input, scaffold fuzz harnesses for them, and wire short-form PR-gating fuzz jobs that complement sanitizer-enabled builds.\n\n## Core Philosophy\n\n\"Coverage-guided fuzzing finds bugs the test suite never imagined.\" Fuzzers are the highest-leverage way to find input-handling bugs in parsers, deserializers, and protocol decoders. Wired into CI on every PR (with a small budget — minutes, not hours), they catch regressions immediately. Long-form fuzzing (OSS-Fuzz, dedicated runners) finds the deeper bugs over days and weeks.\n\n## Natural Language Triggers\n\n- \"set up fuzzing\"\n- \"add libFuzzer to CI\"\n- \"fuzz our parser\"\n- \"OSS-Fuzz integration\"\n- \"property-based tests\"\n\n## Language Coverage (cycle 1)\n\n| Language | Fuzzer            | Property-based alternative |\n|----------|-------------------|----------------------------|\n| C \u002F C++  | libFuzzer (Clang), AFL++ | — |\n| Rust     | cargo-fuzz (libFuzzer-backed), AFL (afl.rs) | proptest, quickcheck |\n| Python   | atheris (libFuzzer-backed) | Hypothesis |\n| Node.js  | jazzer.js (libFuzzer-backed) | fast-check |\n| Java\u002FJVM | jazzer (libFuzzer-backed) | jqwik |\n\nCycle-2 additions: Go (native go-fuzz), Swift, Ruby.\n\n## Execution Flow\n\n### Phase 1: Detect languages\n\nSame `lib\u002Ftoolchain-detect.sh` helper as `sanitizer-in-ci`.\n\n### Phase 2: Identify candidate targets\n\nHeuristics for functions that benefit most from fuzzing:\n\n- Functions taking byte-string or `bytes`\u002F`&[u8]`\u002F`Buffer` input\n- Functions named `parse_*`, `deserialize_*`, `decode_*`, `unmarshal_*`\n- Functions with `from_str` \u002F `from_bytes` constructors\n- Public API entry points that accept untrusted input\n\nThe skill scans declarations using ripgrep:\n\n```bash\n# C\u002FC++ — look for functions taking const uint8_t*\u002Fsize_t pairs\nrg -n --type c --type cpp -e 'parse_|decode_|deserialize_' src\u002F\n\n# Rust\nrg -n --type rust -e 'fn (parse|decode|deserialize)_|FromStr|TryFrom\u003C&\\[u8\\]>' src\u002F\n\n# Python\nrg -n --type py -e 'def (parse|decode|deserialize)' src\u002F\n\n# Node\nrg -n --type js --type ts -e 'function (parse|decode|deserialize)' src\u002F\n```\n\nReport candidates to the operator for confirmation before scaffolding harnesses.\n\n### Phase 3: Scaffold harnesses\n\nReference emitter:\n\n```bash\nagentic\u002Fcode\u002Fframeworks\u002Fsecurity-engineering\u002Fskills\u002Ffuzzing-in-ci\u002Fscripts\u002Femit.sh \\\n  --language auto --ci auto --seconds-per-target 120\n```\n\n#### Example: C libFuzzer harness\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Ffuzz_parse.c`:\n\n```c\n\u002F\u002F LLVMFuzzerTestOneInput is the entry point libFuzzer expects.\n\u002F\u002F Compile with: clang -fsanitize=fuzzer,address,undefined -o fuzz_parse fuzz_parse.c parse.c\n#include \u003Cstdint.h>\n#include \u003Cstddef.h>\n#include \"parse.h\"\n\nint LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    \u002F\u002F Constrain input shape if your parser has a minimum\n    if (size \u003C 4) return 0;\n\n    parse_result_t *r = parse_buffer(data, size);\n    if (r) {\n        parse_result_free(r);\n    }\n    return 0;\n}\n```\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Fseed-corpus\u002F` — populate with a few representative valid inputs.\n\n#### Example: Rust cargo-fuzz harness\n\n`fuzz\u002Ffuzz_targets\u002Ffuzz_parse.rs` (cargo-fuzz layout):\n\n```rust\n#![no_main]\nuse libfuzzer_sys::fuzz_target;\nuse mycrate::parse;\n\nfuzz_target!(|data: &[u8]| {\n    let _ = parse(data);  \u002F\u002F ignore Result; we want it to not panic\u002FUB\n});\n```\n\nProject-side: `cargo install cargo-fuzz` then `cargo fuzz init && cargo fuzz add fuzz_parse`.\n\n#### Example: Python atheris harness\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fpython\u002Ffuzz_parse.py`:\n\n```python\nimport atheris\nimport sys\n\nwith atheris.instrument_imports():\n    from mypkg import parse\n\ndef TestOneInput(data: bytes) -> None:\n    try:\n        parse(data)\n    except (ValueError, mypkg.ParseError):\n        pass  # expected on invalid input\n\natheris.Setup(sys.argv, TestOneInput)\natheris.Fuzz()\n```\n\n#### Example: Node jazzer.js harness\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fnode\u002Ffuzz_parse.js`:\n\n```js\nconst { parse } = require(\"..\u002F..\u002F..\u002Fsrc\");\n\nmodule.exports.fuzz = function (data \u002F* Buffer *\u002F) {\n  try {\n    parse(data);\n  } catch (e) {\n    \u002F\u002F Only catch the parser's documented error class; let everything else propagate\n    if (!(e instanceof require(\"..\u002F..\u002F..\u002Fsrc\").ParseError)) throw e;\n  }\n};\n```\n\n### Phase 4: PR-gating CI recipe\n\nShort-form fuzzing on every PR. Default budget: **2 minutes per target**, with a corpus that grows over time.\n\n#### Example: C libFuzzer in CI\n\n```yaml\n# .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fgithub\u002Fc.yaml\nname: Fuzz (PR)\non:\n  pull_request:\n  push:\n    branches: [main]\n\njobs:\n  libfuzzer:\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - uses: actions\u002Fcheckout@34e114876b0b11c390a56381ad16ebd13914f8d5  # v4.3.1\n      - name: Install clang\n        run: apt-get update && apt-get install -y clang\n      - name: Cache fuzz corpus\n        uses: actions\u002Fcache@5a3ec84eff668545956fd18022155c47e93e2684  # v4.2.3\n        with:\n          path: .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Fcorpus\n          key: fuzz-c-corpus-${{ github.run_id }}\n          restore-keys: fuzz-c-corpus-\n      - name: Build fuzz target\n        run: clang -fsanitize=fuzzer,address,undefined -O1 -g -o fuzz_parse \\\n                .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Ffuzz_parse.c src\u002Fparse.c\n      - name: Fuzz for 120 seconds\n        run: |\n          mkdir -p .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Fcorpus\n          .\u002Ffuzz_parse -max_total_time=120 \\\n            .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Fcorpus \\\n            .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fc\u002Fseed-corpus\n      - name: Upload crashes\n        if: failure()\n        uses: actions\u002Fupload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882  # v4.4.3\n        with:\n          name: fuzz-crashes-c\n          path: crash-*\n```\n\n### Phase 5: OSS-Fuzz integration guide\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002FOSS-FUZZ.md`:\n\n```markdown\n# OSS-Fuzz Integration\n\nOSS-Fuzz runs continuous fuzzing on Google infrastructure for free, for qualifying open-source projects.\n\n## Eligibility\n\n- Open-source project with significant impact (usage in production, dependency of widely-used software, etc.)\n- Submit via https:\u002F\u002Fgithub.com\u002Fgoogle\u002Foss-fuzz\u002Fblob\u002Fmaster\u002Fdocs\u002Fgetting-started\u002Fnew_project_guide.md\n\n## Required files\n\nFor a project named `myproject`, OSS-Fuzz needs:\n\n1. `projects\u002Fmyproject\u002Fproject.yaml` — homepage, language, sanitizers\n2. `projects\u002Fmyproject\u002FDockerfile` — build environment\n3. `projects\u002Fmyproject\u002Fbuild.sh` — compiles fuzz targets\n\nExample:\n\n```yaml\n# project.yaml\nhomepage: \"https:\u002F\u002Fexample.com\u002Fmyproject\"\nlanguage: c\nprimary_contact: \"security@example.com\"\nauto_ccs:\n  - \"another-maintainer@example.com\"\nsanitizers:\n  - address\n  - undefined\n  - memory  # optional, requires MSan-clean deps\n```\n\n## Workflow\n\n1. OSS-Fuzz builds your fuzz targets daily from your repo\n2. Runs them continuously on shared infrastructure\n3. New crashes filed as private bugs to your maintainer-contact list\n4. Crashes auto-disclose 90 days after report OR when patched (whichever first)\n\n## Local testing\n\n```bash\n# Mirror what OSS-Fuzz does locally:\npython infra\u002Fhelper.py build_image myproject\npython infra\u002Fhelper.py build_fuzzers --sanitizer address myproject\npython infra\u002Fhelper.py run_fuzzer myproject fuzz_parse\n```\n```\n\n### Phase 6: Property-based testing recipes\n\nFor languages or codebases where coverage-guided fuzzing is awkward (high-level Python, async-heavy JS, JVM with lots of reflection), property-based testing is often easier to adopt and complementary.\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fpython\u002Fproperty_test.py`:\n\n```python\nfrom hypothesis import given, strategies as st\nfrom mypkg import parse, serialize\n\n@given(st.binary(min_size=0, max_size=10_000))\ndef test_parse_never_panics(data):\n    try:\n        parse(data)\n    except mypkg.ParseError:\n        pass\n\n@given(st.text())\ndef test_roundtrip(s):\n    assert parse(serialize(s)) == s\n```\n\n`.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002Fnode\u002Fproperty_test.js` (fast-check):\n\n```js\nconst fc = require(\"fast-check\");\nconst { parse, serialize } = require(\"..\u002F..\u002F..\u002Fsrc\");\n\ntest(\"roundtrip\", () => {\n  fc.assert(fc.property(fc.string(), (s) => parse(serialize(s)) === s));\n});\n\ntest(\"parse handles arbitrary bytes\", () => {\n  fc.assert(\n    fc.property(fc.uint8Array(), (bytes) => {\n      try { parse(Buffer.from(bytes)); } catch (e) { \u002F* expected *\u002F }\n    })\n  );\n});\n```\n\n## Composition\n\n- `sanitizer-in-ci` — fuzzers find inputs that trigger UB; sanitizers detect the UB. Pair them.\n- `ci-action-pinning` — all action SHAs are pinned.\n\n## Implementation Status\n\n- `scripts\u002Femit.sh` emits starter harnesses under `.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002F{language}\u002F`.\n- PR-gating recipes are emitted under `.aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002F{ci-platform}\u002F`.\n- The emitter also creates starter `OSS-FUZZ.md` and `merge_corpus.sh` placeholders.\n- Project-specific target binding is still required: replace placeholder parser calls with real APIs and seed corpora.\n\n## References\n\n- @$AIWG_ROOT\u002Fagentic\u002Fcode\u002Fframeworks\u002Fsecurity-engineering\u002Fskills\u002Fsanitizer-in-ci\u002FSKILL.md — Companion sanitizer skill\n- `.aiwg\u002Fsecurity\u002Fcurl-checklist-gap-analysis.md` row 16\n- libFuzzer: https:\u002F\u002Fllvm.org\u002Fdocs\u002FLibFuzzer.html\n- cargo-fuzz: https:\u002F\u002Fgithub.com\u002Frust-fuzz\u002Fcargo-fuzz\n- atheris: https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fatheris\n- jazzer.js: https:\u002F\u002Fgithub.com\u002FCodeIntelligenceTesting\u002Fjazzer.js\n- AFL++: https:\u002F\u002Faflplus.plus\u002F\n- OSS-Fuzz: https:\u002F\u002Fgoogle.github.io\u002Foss-fuzz\u002F\n- Hypothesis: https:\u002F\u002Fhypothesis.readthedocs.io\u002F\n- fast-check: https:\u002F\u002Fgithub.com\u002Fdubzzz\u002Ffast-check\n- proptest (Rust): https:\u002F\u002Fgithub.com\u002Fproptest-rs\u002Fproptest\n",{"name":5,"errors":59,"script":64,"ensures":68,"requires":75,"namespace":80,"platforms":81,"invariants":83,"commandHint":86,"description":7},[60,62],{"no-supported-language":61},"project has no language this skill can wire fuzzers for",{"no-candidate-targets":63},"skill scanned for fuzz-worthy functions but found none; suggest manual seeding",{"cwd":65,"runtime":43,"argsHint":66,"entrypoint":67},"project-root","[--language c|cpp|rust|go|python|node|auto] [--ci gitea|github|gitlab|auto] [--seconds-per-target N] [--coverage] [--oss-fuzz]","scripts\u002Femit.mjs",[69,71,73],{"harness-scaffolds":70},"starter fuzz harness(es) at .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002F{language}\u002F",{"ci-recipe":72},"PR-gating short-form fuzz job(s) at .aiwg\u002Fsecurity-engineering\u002Ffuzzing\u002F{ci-platform}\u002F",{"long-form-guide":74},"documentation for OSS-Fuzz integration and dedicated-runner patterns",[76,78],{"toolchain":77},"at least one supported language detected (C, C++, Rust, Python, Node)",{"ci-platform":79},"known CI platform (Gitea Actions, GitHub Actions, GitLab CI)","aiwg",[82],"all",[84,85],"PR-gating fuzz runs are bounded (default 2 minutes per target) — never blocks PR indefinitely","long-form fuzzing is documented separately and never runs inline in PR jobs",{"model":45,"category":53,"modelRole":87,"modelTier":88,"allowedTools":89,"argumentHint":66,"orchestration":55},"efficiency","economy","Read, Write, Bash, Glob, Grep","main","6754967c344ccb087a8de06972f55a41067b291b","agentic\u002Fcode\u002Fplugins\u002Fsecurity-engineering\u002Fskills\u002Ffuzzing-in-ci",36,"https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg","https:\u002F\u002Faiwg.io","https:\u002F\u002Fgithub.com\u002Fjmagly","https:\u002F\u002Fintegrolabs.io","ml\u002Fai, industrial automation, safety\u002Fsecurity, ssi\r\n\r\nmagly.net\r\nintegrolabs.io\r\naiwg.io\r\nfortemi.com\r\npagenary.com\r\nbytecask.com","2026-11-14 10:46:34",{"source":8,"skillName":5,"commands":101,"prompt":111,"zipAvailable":112},[102,105,108],{"tool":103,"command":104},"npx","npx skills add jmagly\u002Faiwg --skill fuzzing-in-ci",{"tool":106,"command":107},"bunx","bunx skills add jmagly\u002Faiwg --skill fuzzing-in-ci",{"tool":109,"command":110},"pnpm","pnpm dlx skills add jmagly\u002Faiwg --skill fuzzing-in-ci","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fplugins\u002Fsecurity-engineering\u002Fskills\u002Ffuzzing-in-ci\u002FSKILL.md",true,[114,119],{"path":67,"resourceType":115,"resourceTypeDesc":116,"sizeBytes":117,"sourceHtmlUrl":118},"SCRIPT","脚本",4946,"https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fplugins\u002Fsecurity-engineering\u002Fskills\u002Ffuzzing-in-ci\u002Fscripts\u002Femit.mjs",{"path":120,"resourceType":115,"resourceTypeDesc":116,"sizeBytes":121,"sourceHtmlUrl":122},"scripts\u002Femit.sh",135,"https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fplugins\u002Fsecurity-engineering\u002Fskills\u002Ffuzzing-in-ci\u002Fscripts\u002Femit.sh",[124,149,172,178,185,199],{"skillNo":125,"name":126,"nameZh":6,"description":127,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":128,"categories":129,"keywords":131,"publishedAt":54},"01M70QA0BSYJ49EES9V4RE8QH1","host-hardening","Read-only system hardening baseline and plan-first host hardening recommendations for SSH, Docker bind addresses, firewall persistence, datastores, exporters and audit retention.","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fplugins\u002Fsecurity-engineering\u002Fskills\u002Fhost-hardening\u002FSKILL.md",[130],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[132,133,134,27,135,136,137,138,139,140,46,141,142,143,144,37,145,146,147,148],"host","host hardening","hardening","re","recommendations","remediation","plan","port","verification","access","only","retention","audit","firewall","bind","secrets","request",{"skillNo":150,"name":151,"nameZh":6,"description":152,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":153,"categories":154,"keywords":159,"publishedAt":54},"01M70PNT2Z4HMZPRBTAF6073NN","exposure-analysis","Read-only firewall analysis and effective host exposure reconstruction for Docker published ports, UFW bypass, stale rules, CDN scope, IPv6 asymmetry and external probe allowlists.","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fplugins\u002Fforensics\u002Fskills\u002Fexposure-analysis\u002FSKILL.md",[155,158],{"categoryNo":156,"categoryName":157,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000011","运维与部署",{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[160,161,162,27,163,139,164,165,46,166,132,167,142,168,169,37,145,170,171,40],"exposure analysis","analysis","unknown","credentials","collection","ufw","ports","internet","local","scope","reconstruction","operator",{"skillNo":173,"name":126,"nameZh":6,"description":127,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":174,"categories":175,"keywords":177,"publishedAt":54},"01M70P8QATMPKA78E4FT5D2TNA","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fframeworks\u002Fsecurity-engineering\u002Fskills\u002Fhost-hardening\u002FSKILL.md",[176],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[134,132,133,141,27,148,137,136,144,138,139,140,46,147,142,143,135,37,145,146],{"skillNo":179,"name":151,"nameZh":6,"description":152,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":180,"categories":181,"keywords":184,"publishedAt":54},"01M70NMPVJ5H0JH131P60FW4R8","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fframeworks\u002Fforensics-complete\u002Fskills\u002Fexposure-analysis\u002FSKILL.md",[182,183],{"categoryNo":156,"categoryName":157,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[161,160,37,163,139,164,46,162,132,167,142,168,169,27,145,166,165,170,171,40],{"skillNo":186,"name":187,"nameZh":6,"description":188,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":189,"categories":190,"keywords":192,"publishedAt":54},"01M6CB4DDR0B4NNCFK7ZK7449H","fixture-skill","Exercise rule delivery.","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frule-delivery\u002Fskills\u002Ffixture-skill\u002FSKILL.md",[191],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[193,194,195,196,197,198],"fixture skill","fixture","rule","delivery","true","exercise",{"skillNo":200,"name":201,"nameZh":6,"description":202,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":203,"categories":204,"keywords":206,"publishedAt":54},"01M6CB4AVK1W76MFMPP0JP32CJ","pi-local","Pi-local duplicate-precedence fixture.","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Fproviders\u002Fpi\u002Fproject\u002F.pi\u002Fskills\u002Fpi-local\u002FSKILL.md",[205],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[207,208,168,209,194],"pi","pi local","duplicate"]