A memory-safe Rust port of libinjection, the SQL injection and XSS detection library. The original translation from C was AI-generated (a "vibe port": an AI plan from GPT-5, executed with Claude Code, with little of the code manually reviewed line by line). This fork exists to make that port trustworthy by measurement rather than by reading: it is differential-tested against the C library it was ported from, and this README describes what that testing currently shows.
- SQL injection detection with fingerprinting
- XSS detection with context awareness
- No
unsafe, and lints that deny the common panic sources (see Linting) - Minimal heap allocations using
SmallVec
Correctness here means one thing: the same answer as the C library. That is measured, not asserted, by comparison-bin/tests/differential.rs, which links the C sources through the FFI harness and compares this port against them over libinjection's own corpus of ~163,000 inputs, on both verdicts and fingerprints.
No known divergence from the C library remains. SQLi fingerprints and XSS verdicts match exactly across the whole corpus (0 of 162,963 each), and the NUL-in-$-token edge, which the text corpus cannot reach, is matched too and held by a dedicated test. Any divergence outside this state fails the build.
The fixes that got here, each following the C control flow rather than a particular input:
- multi-word keyword folding by table presence (
LOCK IN SHARE MODE) - a case-insensitive
INTOcheck in the three-token whitelist (into outfile) - a length-limited XSS event-handler check (
onerror%09=) - the
strchr-over-a-literal family, where C counts an embedded NUL as a set member (itsstrchrfinds the accept string's terminator):strlenspn/strlencspnin the number, money and variable scans, and NUL as whitespace in bothchar_is_whiteand the HTML5h5_is_white sp_passwordand the collate_check searched over the raw bytes, as C does, rather than a lossily decoded string- a variable token value stored without the leading
@, so the function fold matches a name like@pasSword
This is not the same as "provably identical", but the measured gap is small and shrinking. Over a two-hour differential-fuzzing campaign the SQLi detector found no divergence at all. The XSS detector's one finding was a bug in the C library rather than the port: an ASan-confirmed out-of-bounds read in htmlencode_startswith, whose verdict then depends on whatever sits past the buffer. The FFI harness zero-pads the C input so that read is defined and the comparison is deterministic; the memory-safe port never reads past the input. Treat this port as a close match with a measured gap of zero on the corpus, not as a drop-in replacement whose every answer is guaranteed.
CI runs on every push and pull request:
- Lints and unit tests across the workspace.
- Library coverage (
cargo-llvm-cov) with an enforced floor. - Differential against the C library — the job that matters, described above. A divergence fails it.
- Differential fuzzing (two minutes per detector on each push, and a longer scheduled campaign). It reports rather than gates: a probabilistic run is a weak signal to block a merge on, so the corpus differential is the gate and this job keeps any new class visible. The C side runs through the zero-padded harness, so a divergence it reports is a genuine parse difference rather than C reading past the buffer.
A separate 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.
use libinjectionrs::{detect_sqli, detect_xss};
let input = b"1' OR '1'='1";
if detect_sqli(input).is_injection() {
// handle SQL injection
}
if detect_xss(b"<script>alert('xss')</script>").is_injection() {
// handle XSS
}Fetch the C library submodule first; the differential test and the FFI harness need it:
git submodule update --init --recursive
cargo test # unit tests
cargo test -p libinjection-comparison --test differential # against the C librarycomparison-bin and libinjection-debug compare and trace this port against C; reach for them before writing new probes.
Third-party warnings are allowed, but the workspace denies unsafe, unwrap, expect, panic, unreachable, todo, and unimplemented in the library:
cargo clippy --workspace --all-targets -- -A warningsThe fuzz targets under fuzz/ compare each detector against C on generated input. scripts/seed_fuzz_corpus.sh seeds their corpora from libinjection's own test-sqli-*.txt and test-html5-*.txt cases, de-duplicated by hash:
./scripts/seed_fuzz_corpus.sh sqli # SQLi corpus
./scripts/seed_fuzz_corpus.sh xss # XSS corpus
./scripts/seed_fuzz_corpus.sh all # bothlibinjectionrs/ Main Rust library source
comparison-bin/ Differential test and CLI comparison against C
libinjection-debug/ Token-level tracing tools for comparing implementations
ffi-harness/ C FFI harness the differential test links against
fuzz/ Differential fuzz targets and corpora
benches/ Benchmarks
libinjection-c/ Git submodule: the original C library
docs/ Architecture and porting notes
scripts/ Corpus generation
Licensed under the BSD 3-Clause License (LICENSE or https://opensource.org/licenses/BSD-3-Clause). This is a Rust port of libinjection, also BSD 3-Clause.