A vibe port (AI translation without manually reviewing much of the code) of the libinjection library from C to memory-safe Rust. Libinjection is a library for SQL injection and XSS attack detection in strings. The port was done with an original plan created with GPT-5 and then mostly executed with Claude Code.
- SQL injection detection with fingerprinting
- XSS detection with context awareness
- Minimal heap allocations using
SmallVec
- While the AI did all of the coding work, its process was supervised by a human and most of its outputs required additional correction prompts.
- All the test files for the C library are run by the Rust library and pass.
- Linting has been configured both to deny unsafe code and many conditions that could result in panics in the library, excluding slice indexing which could theoretically still panic (tests and debug tools still allow panics).
- CI runs on every push and pull request: lints, unit tests, the differential test below, and two minutes of differential fuzzing per detector. The fuzz job reports rather than gates, because it currently finds new divergence classes faster than they can be fixed.
comparison-bin/tests/differential.rscompares this port against the C library over libinjection's own corpus (~163,000 inputs), on both verdicts and fingerprints. Divergences outside the known classes below fail the build.- A test asserts that neither detector panics on adversarial input: every one- and two-byte value including NUL, random metacharacter strings, and 50,000-byte pathological repeats.
Measured by cargo test -p libinjection-comparison --test differential.
Both are false negatives, so both are missed detections.
| Area | Symptom | Status |
|---|---|---|
| SQLi | SQL keywords of three or more words are not folded into a single keyword token. LOCK IN SHARE MODE fingerprints k in C and nnnn here; x IN BOOLEAN MODE gives nk and nnn. Two-word keywords such as INTO OUTFILE fold correctly on their own, and every intermediate prefix is present in the keyword table, so the defect is in chaining the merge rather than in the data. |
10 verdict divergences, 1,631 fingerprint divergences (~1% of the corpus) |
| XSS | Whitespace or a control byte between an attribute name and its = is not recognised, as in <img src=x onerror%09="alert(1)">. |
14 verdict divergences |
| SQLi | A NUL byte inside a $-prefixed token changes tokenization in C but not here: '$\0T fingerprints s1n in C and snn here, so T'$\0T# is an injection to C and clean here. Without the NUL both give snn. | pinned by a dedicated test |
The fingerprint count is the better measure of drift: the verdict surviving a tokenization difference is luck rather than correctness, so the 1,631 is the number to drive down.
These are the classes characterised so far, not a complete list. Once the fuzz
targets stopped skipping NUL bytes they began finding a new class every few
minutes, including at least one false positive ('/@@\0... is flagged here
and not by C). Enumerating the rest is open-ended, which is why the fuzz job
reports instead of gating.
libinjectionrs/
├── benches/ # Performance benchmarks
├── comparison-bin/ # Tools for comparing Rust vs C behavior
├── docs/ # Architecture and porting documentation
├── ffi-harness/ # C FFI testing harness
├── fuzz/ # Fuzzing targets and corpora
├── libinjection-c/ # Git submodule with original C library
├── libinjection-debug/ # Debug tools for comparing implementations
├── libinjectionrs/ # Main Rust library source code
└── scripts/ # Build and corpus generation scripts
cargo clippy --workspace --all-targets -- -A warnings
To get started with development, first fetch the git submodule containing the original C library:
git submodule update --init --recursiveuse libinjectionrs::{detect_sqli, detect_xss};
// SQL injection detection
let input = b"1' OR '1'='1";
let result = detect_sqli(input);
if result.is_injection() {
println!("SQL injection detected: {:?}", result.fingerprint);
}
// XSS detection
let input = b"<script>alert('xss')</script>";
let result = detect_xss(input);
if result.is_injection() {
println!("XSS detected");
}Scripts create fuzz corpuses: What the script does:
-
SQLi corpus: Extracts 50 SQL injection test cases from test-sqli-*.txt files
-
XSS corpus: Extracts 63 HTML/XSS test cases from test-html5-*.txt files
-
Deduplication: Uses SHA1 hashes to avoid duplicate entries
-
Proper naming: Prefixes seeded files with seed_sqli_ or seed_xss_
Usage:
./scripts/seed_fuzz_corpus.sh sqli # Seed SQLi corpus only
./scripts/seed_fuzz_corpus.sh xss # Seed XSS corpus only
./scripts/seed_fuzz_corpus.sh all # Seed both corpora
Licensed under the BSD 3-Clause License (LICENSE or https://opensource.org/licenses/BSD-3-Clause).
This project is a Rust port of libinjection, which is also licensed under the BSD 3-Clause License.