Claude
Skills
Sign in
Back

fuzzing-in-ci

Included with Lifetime
$97 forever

Detect candidate fuzz targets and emit CI recipes for libFuzzer/AFL/cargo-fuzz/atheris/fast-check harnesses, plus OSS-Fuzz integration patterns

Cloud & DevOpsscripts

What this skill does


# Fuzzing in CI

**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.

## Core Philosophy

"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.

## Natural Language Triggers

- "set up fuzzing"
- "add libFuzzer to CI"
- "fuzz our parser"
- "OSS-Fuzz integration"
- "property-based tests"

## Language Coverage (cycle 1)

| Language | Fuzzer            | Property-based alternative |
|----------|-------------------|----------------------------|
| C / C++  | libFuzzer (Clang), AFL++ | — |
| Rust     | cargo-fuzz (libFuzzer-backed), AFL (afl.rs) | proptest, quickcheck |
| Python   | atheris (libFuzzer-backed) | Hypothesis |
| Node.js  | jazzer.js (libFuzzer-backed) | fast-check |
| Java/JVM | jazzer (libFuzzer-backed) | jqwik |

Cycle-2 additions: Go (native go-fuzz), Swift, Ruby.

## Execution Flow

### Phase 1: Detect languages

Same `lib/toolchain-detect.sh` helper as `sanitizer-in-ci`.

### Phase 2: Identify candidate targets

Heuristics for functions that benefit most from fuzzing:

- Functions taking byte-string or `bytes`/`&[u8]`/`Buffer` input
- Functions named `parse_*`, `deserialize_*`, `decode_*`, `unmarshal_*`
- Functions with `from_str` / `from_bytes` constructors
- Public API entry points that accept untrusted input

The skill scans declarations using ripgrep:

```bash
# C/C++ — look for functions taking const uint8_t*/size_t pairs
rg -n --type c --type cpp -e 'parse_|decode_|deserialize_' src/

# Rust
rg -n --type rust -e 'fn (parse|decode|deserialize)_|FromStr|TryFrom<&\[u8\]>' src/

# Python
rg -n --type py -e 'def (parse|decode|deserialize)' src/

# Node
rg -n --type js --type ts -e 'function (parse|decode|deserialize)' src/
```

Report candidates to the operator for confirmation before scaffolding harnesses.

### Phase 3: Scaffold harnesses

Reference emitter:

```bash
agentic/code/frameworks/security-engineering/skills/fuzzing-in-ci/scripts/emit.sh \
  --language auto --ci auto --seconds-per-target 120
```

#### Example: C libFuzzer harness

`.aiwg/security-engineering/fuzzing/c/fuzz_parse.c`:

```c
// LLVMFuzzerTestOneInput is the entry point libFuzzer expects.
// Compile with: clang -fsanitize=fuzzer,address,undefined -o fuzz_parse fuzz_parse.c parse.c
#include <stdint.h>
#include <stddef.h>
#include "parse.h"

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Constrain input shape if your parser has a minimum
    if (size < 4) return 0;

    parse_result_t *r = parse_buffer(data, size);
    if (r) {
        parse_result_free(r);
    }
    return 0;
}
```

`.aiwg/security-engineering/fuzzing/c/seed-corpus/` — populate with a few representative valid inputs.

#### Example: Rust cargo-fuzz harness

`fuzz/fuzz_targets/fuzz_parse.rs` (cargo-fuzz layout):

```rust
#![no_main]
use libfuzzer_sys::fuzz_target;
use mycrate::parse;

fuzz_target!(|data: &[u8]| {
    let _ = parse(data);  // ignore Result; we want it to not panic/UB
});
```

Project-side: `cargo install cargo-fuzz` then `cargo fuzz init && cargo fuzz add fuzz_parse`.

#### Example: Python atheris harness

`.aiwg/security-engineering/fuzzing/python/fuzz_parse.py`:

```python
import atheris
import sys

with atheris.instrument_imports():
    from mypkg import parse

def TestOneInput(data: bytes) -> None:
    try:
        parse(data)
    except (ValueError, mypkg.ParseError):
        pass  # expected on invalid input

atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()
```

#### Example: Node jazzer.js harness

`.aiwg/security-engineering/fuzzing/node/fuzz_parse.js`:

```js
const { parse } = require("../../../src");

module.exports.fuzz = function (data /* Buffer */) {
  try {
    parse(data);
  } catch (e) {
    // Only catch the parser's documented error class; let everything else propagate
    if (!(e instanceof require("../../../src").ParseError)) throw e;
  }
};
```

### Phase 4: PR-gating CI recipe

Short-form fuzzing on every PR. Default budget: **2 minutes per target**, with a corpus that grows over time.

#### Example: C libFuzzer in CI

```yaml
# .aiwg/security-engineering/fuzzing/github/c.yaml
name: Fuzz (PR)
on:
  pull_request:
  push:
    branches: [main]

jobs:
  libfuzzer:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5  # v4.3.1
      - name: Install clang
        run: apt-get update && apt-get install -y clang
      - name: Cache fuzz corpus
        uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684  # v4.2.3
        with:
          path: .aiwg/security-engineering/fuzzing/c/corpus
          key: fuzz-c-corpus-${{ github.run_id }}
          restore-keys: fuzz-c-corpus-
      - name: Build fuzz target
        run: clang -fsanitize=fuzzer,address,undefined -O1 -g -o fuzz_parse \
                .aiwg/security-engineering/fuzzing/c/fuzz_parse.c src/parse.c
      - name: Fuzz for 120 seconds
        run: |
          mkdir -p .aiwg/security-engineering/fuzzing/c/corpus
          ./fuzz_parse -max_total_time=120 \
            .aiwg/security-engineering/fuzzing/c/corpus \
            .aiwg/security-engineering/fuzzing/c/seed-corpus
      - name: Upload crashes
        if: failure()
        uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882  # v4.4.3
        with:
          name: fuzz-crashes-c
          path: crash-*
```

### Phase 5: OSS-Fuzz integration guide

`.aiwg/security-engineering/fuzzing/OSS-FUZZ.md`:

```markdown
# OSS-Fuzz Integration

OSS-Fuzz runs continuous fuzzing on Google infrastructure for free, for qualifying open-source projects.

## Eligibility

- Open-source project with significant impact (usage in production, dependency of widely-used software, etc.)
- Submit via https://github.com/google/oss-fuzz/blob/master/docs/getting-started/new_project_guide.md

## Required files

For a project named `myproject`, OSS-Fuzz needs:

1. `projects/myproject/project.yaml` — homepage, language, sanitizers
2. `projects/myproject/Dockerfile` — build environment
3. `projects/myproject/build.sh` — compiles fuzz targets

Example:

```yaml
# project.yaml
homepage: "https://example.com/myproject"
language: c
primary_contact: "[email protected]"
auto_ccs:
  - "[email protected]"
sanitizers:
  - address
  - undefined
  - memory  # optional, requires MSan-clean deps
```

## Workflow

1. OSS-Fuzz builds your fuzz targets daily from your repo
2. Runs them continuously on shared infrastructure
3. New crashes filed as private bugs to your maintainer-contact list
4. Crashes auto-disclose 90 days after report OR when patched (whichever first)

## Local testing

```bash
# Mirror what OSS-Fuzz does locally:
python infra/helper.py build_image myproject
python infra/helper.py build_fuzzers --sanitizer address myproject
python infra/helper.py run_fuzzer myproject fuzz_parse
```
```

### Phase 6: Property-based testing recipes

For 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.

`.aiwg/security-engineering/fuzzing/python/property_test.py`:

```python
from hypothesis import given, strategies as st
from mypkg import parse, serialize

@given(st.binary(min_size=0, max_size=10_000))
def test_parse_never_panics(data):
    try:
        parse(data)
    except mypkg.ParseError:
        pass

@given(st.text())
def test_roundtrip(s):
    assert parse(serialize(s)) == s
```

`.aiwg/security-engineering/fuzzing/node/property_te

Related in Cloud & DevOps