AI now writes production code faster than any security team can review it. The two classes of tools we built to catch its mistakes each force a bad trade-off — and OpenTaint exists to break that trade-off. This is a complete, run-it-yourself guide: what the tool is, how taint analysis works, how to install and scan, four worked examples, and the AI agent workflows that let it scale.
TL;DR
- Open-source, formal, inter-procedural taint analysis engine — an Apache-2.0 alternative to Semgrep Pro and CodeQL.
- Tracks untrusted data across function boundaries, persistence layers, aliases, and async code.
- Let's an LLM agent distill one finding into a deterministic rule — you pay the model once, not on every scan.
- Replays that rule across your whole codebase, on every commit, at zero token cost.
- Deepest coverage today for Java / Kotlin / Spring ; Python, Go, C#, JS & TS on the roadmap.
Note
BlackArch Linux
We also provide a ready-to-deploy BlackArch Linux VM that can be launched instantly on AWS , GCP , or Azure . No installation, setup, or dependency management required — just spin it up and start using a full arsenal of penetration testing and security auditing tools in minutes.
Kali GUI Linux
Our Kali GUI Linux VM comes fully pre-configured with a graphical interface, making it easy for both beginners and professionals to get started. Deploy directly on AWS , GCP , or Azure with zero setup — no installation hassles, just immediate access to a complete offensive security toolkit.
Browser-Based Kali Linux
We offer a browser-based Kali Linux environment that runs entirely in the cloud. Simply deploy and access it from your browser — no downloads, no local setup, no compatibility issues. Deploy directly on AWS , GCP , or Azure with zero setup — no installation hassles, just immediate access to a complete offensive security toolkit. Perfect for quick testing, learning, and remote security operations from anywhere.
ParrotOS Linux
Our ParrotOS Linux VM is optimized for security, privacy, and development workflows. Available for instant deployment on AWS , GCP , and Azure , it eliminates the need for manual installation — giving you a secure, ready-to-use environment in just a few clicks.
1. What is OpenTaint?
OpenTaint is a static application security testing (SAST) engine focused on one thing done extremely well: tracking the flow of untrusted data through your program. It is written in Go, self-hostable, and ships as one stack — engine, rules, and CI integrations — under Apache 2.0 (engine) and MIT (CLI, GitHub Action, GitLab template, rules).
Three sentences capture the whole pitch:
- It finds what pattern matchers miss. A formal inter-procedural dataflow engine follows tainted input even when it crosses functions, gets stored and re-read, or is aliased.
- It pays the model once, not on every scan. An AI agent turns a single confirmed vulnerability into a reusable taint rule; the deterministic engine then replays it in minutes of CPU.
- It is battery-included and open. Today, it is the most thorough taint engine for Java / Kotlin / Spring , with Python, Go, C#, JavaScript, and TypeScript on the roadmap.
2. Taint analysis in 60 seconds
“Taint” is a label. You mark certain inputs as untrusted (a source ), and certain dangerous operations as things that must never receive untrusted data (a sink ). The engine then asks a single question: Can data flow from any source to any sink? If yes — and nothing along the way neutralizes it (a sanitizer ) — that path is a vulnerability.
SOURCE PROPAGATION SINK
req.getParameter() → service.process(x) → statement.execute(sql)
(untrusted input) (taint flows across (dangerous op:
function boundaries) SQL injection!)
▲ a sanitizer anywhere on this path (e.g. a parameterized
query / encoder) would "clean" the taint and kill the finding
The hard part is propagation. Naive tools only look at a single line or function (intra-procedural). Real bugs span many hops: controller → service → repository → ORM. Following taint across all those hops is inter-procedural analysis, and it is exactly what OpenTaint specializes in.
3. Why it matters — the AI-era gap
There are two existing families of tools, and each makes one painful compromise:
The deep, inter-procedural analysis that actually catches data-flow bugs has historically been locked inside proprietary tools. OpenTaint opens it up and makes the LLM a one-time rule author rather than a per-scan expense.
4. How OpenTaint works under the hood
The pipeline, conceptually, is four stages:
- Build & parse. OpenTaint understands your build so it can resolve types, dependencies, and method targets — this is what enables real inter-procedural reasoning rather than guessing.
- Model the graph. It constructs a call graph and dataflow graph, including aliasing and (for Spring) framework-specific wiring like controllers, request mappings, and beans.
- Apply rules. Rules declare sources, sinks, sanitizers, and library “pass-through” approximations (how data moves through code it can’t see, e.g., third-party libs).
- Solve & report. The engine computes reachable source→sink paths and emits results, typically as SARIF, so any IDE or CI can consume them.
Why SARIF matters
SARIF is the standard interchange format for static analysis. Because OpenTaint emits SARIF, findings render natively in GitHub code scanning, VS Code, and most security dashboards — no custom glue required.
5. Installation — every method
Pick whichever fits your environment. All commands below are taken from the official quick-start.
Install script (Linux / macOS)
The installer detects your platform, verifies a checksum, and drops the binary in ~/.opentaint/install, and prints the PATH line to add to your shell profile:
curl -fsSL https://opentaint.org/install.sh | bash
Homebrew (Linux / macOS)
brew install --cask seqra/tap/opentaint
Windows (PowerShell)
irm https://opentaint.org/install.ps1 | iex
npm (cross-platform)
# global install
npm install -g @seqra/opentaint
# or run instantly, no install (needs Node.js)
npx @seqra/opentaint scan
Verify before piping to a shell
Piping a remote script straight into bash or It iex is convenient but executes whatever the server returns. On shared or production machines, download the script first, read it, then run it — or prefer Homebrew/npm, which are checksum-backed.
6. Set up a test project & verify
Scaffold a sample Spring app to test against
No project handy? Spin up a throwaway Spring Boot app straight from start.spring.io, unzip it, and boot it once to confirm your toolchain (Java 21 + the Maven wrapper). This gives OpenTaint something real to chew on:
curl https://start.spring.io/starter.zip \
-d type=maven-project -d language=java -d bootVersion=3.5.4 \
-d baseDir=spring-app -d groupId=com.example -d artifactId=spring-app \
-d name=spring-app -d packageName=com.example.springapp \
-d javaVersion=21 -d dependencies=web -o spring-app.zip
unzip spring-app.zip && rm spring-app.zip
cd spring-app
chmod +x mvnw # the wrapper ships without the exec bit
./mvnw spring-boot:run # downloads Maven + Boot, then starts Tomcat on :8080
A couple of gotchas (shown above)
Run ./mvnw from inside the project (not the parent folder), and the wrapper needs to be chmod +x mvnw first. You only need java to install the wrapper that fetches Maven for you, so a missing mvn is fine. Stop the app with Ctrl-COpenTaint analyzes the source, so it never needs the app actually to run.
Verify OpenTaint
Confirm the binary is on your PATH and skim the available commands — OpenTaint is a Cobra-style CLI with subcommands for compiling, pulling artifacts, scanning, and summarizing SARIF:
opentaint --help
opentaint --version
7. Your first scan
From inside the project, just run scan. OpenTaint compiles a project model , runs the analyzer, applies the bundled ruleset, and writes a SARIF report into ~/.opentaint/cache, and prints a clean box-drawing summary:
opentaint scan
A fresh, hello-world scaffold has nothing dangerous in it, so the first scan reports 0 findings — exactly what you want to confirm the toolchain end-to-end before you introduce real code:
╭─OpenTaint Compile and Scan─╮
╰─┬──────────────────────────╯
├─ Project └─ ~/projects/spring-app
├─ Project model └─ ~/.opentaint/cache/spring-app-cba2bab8/project-model
├─ Autobuilder └─ custom (~/.opentaint/install/lib/opentaint-project-auto-builder.jar)
├─ Analyzer └─ custom (~/.opentaint/install/lib/opentaint-project-analyzer.jar)
└─ Bundled ruleset└─ custom (~/.opentaint/install/lib/rules)
✓ Compiling project model in 15s
✓ Analyzing project in 17s
╭─Scan Summary─╮
╰─┬────────────╯
├─ Findings
│ ├─ Total: 0 findings
│ ├─ Files affected: 0
│ ├─ Rules executed: 78
│ └─ Rules triggered: 0
└─ Output
├─ Report: …/project-model/sources/opentaint.sarif
└─ Log: ~/.opentaint/logs/spring-app-cba2bab8/…log
The scan doesn’t dump findings inline — it writes a SARIF report and points you at the summary subcommand. Pass --show-findings to print each finding (here, none yet):
opentaint summary ~/.opentaint/cache/spring-app-cba2bab8/project-model/sources/opentaint.sarif --show-findings
8. Hands-on examples
Four progressively richer examples, from a vulnerable Spring endpoint to a custom rule and CI output.
Example 1 — Catching cross-function SQL injection
Here is the kind of bug AST matchers routinely miss, because the source and sink live in different files and the taint flows through a service layer:
@RestController
public class UserController {
private final UserService service;
@GetMapping("/users/search")
public List<User> search(@RequestParam String name) {
// 'name' is untrusted — this is the SOURCE
return service.find(name);
}
}
@Repository
public class UserRepository {
private final DataSource ds;
public List<User> rawByName(String name) throws SQLException {
String sql = "SELECT * FROM users WHERE name = '" + name + "'";
try (Statement st = ds.getConnection().createStatement()) {
// tainted 'name' reaches a raw query — this is the SINK
return map(st.executeQuery(sql));
}
}
}
A line-by-line linter sees nothing wrong in the controller, and the repository “just builds a string.” OpenTaint connects @RequestParam name → service.find → rawByName → executeQuery and flags the full path. The fix it nudges you toward is a parameterized query, which acts as a sanitizer and removes the finding on the next scan.
Example 2 — Writing a custom taint rule
The real power move: teach OpenTaint about your code. Suppose you have an internal helper Http.body() that returns raw request bodies, and a logging sink AuditLog.write() that must never receive PII. You declare them as a source and sink:
rules:
- id: pii-into-auditlog
severity: high
message: "Untrusted request body flows into AuditLog (PII leak risk)"
sources:
- method: "com.acme.http.Http#body()"
sinks:
- method: "com.acme.audit.AuditLog#write(java.lang.String)"
taint-arg: 0
sanitizers:
- method: "com.acme.privacy.Redactor#redact(java.lang.String)"
# run a scan with your custom rules directory added
opentaint scan --rules ./rules .
This is the cost-saving loop
You (or an agent) write this rule once. From then on, every scan and every future commit is checked against it deterministically — no LLM tokens spent re-discovering the same class of bug.
Example 3 — SARIF output + opening results
Produce machine-readable output and feed it anywhere that speaks SARIF:
opentaint scan --output results.sarif .
# count findings by severity with jq
jq '[.runs[].results[].level] | group_by(.) | map({(.[0]): length}) | add' results.sarif
Open results.sarif in VS Code (with the SARIF Viewer extension) or upload it to GitHub code scanning to get inline annotations on the exact source and sink lines.
Example 4 — Zero-install scan with Docker
No local toolchain? Mount your project and run the published image:
docker run --rm \
-v $(pwd):/project \
-v $(pwd):/output \
ghcr.io/seqra/opentaint:latest \
opentaint scan --output /output/results.sarif /project
This is the most reproducible option — identical engine version every time — which makes it ideal for CI runners and for sharing a scan setup across a team.
9. AI agent workflows
OpenTaint ships agent skills that turn static analysis into an end-to-end AppSec workflow. Install them with:
npx skills add https://github.com/seqra/opentaint
The headline skill, appsec-agent , orchestrates a full project assessment: build the project, run OpenTaint, discover the attack surface, add targeted rules, model missing library data flows, triage findings, and optionally generate dynamic proof-of-concept checks for confirmed vulnerabilities.
The included skills map cleanly onto the security-analysis loop:
Scan & triage
▹ build-project
▹ run-scan
▹ analyze-findings
▹ generate-poc
Coverage expansion
▹ triage-dependencies
▹ discover-attack-surface
▹ create-test-project
▹ create-rule
▹ assemble-lib-rules
Dataflow modeling
▹ analyze-external-methods
▹ create-pass-through-approximation
▹ create-dataflow-approximation
▹ debug-rule
▹ report-analyzer-issue
The pattern that makes this scale
The agent does the creative, one-time work — understanding your attack surface and authoring rules and library approximations. The deterministic engine does the repetitive, forever work — replaying those rules on every commit. That division is the entire economic argument for OpenTaint.
10. CI/CD integration
Because OpenTaint emits SARIF and ships a GitHub Action + GitLab template, wiring it into a pipeline is short. A minimal GitHub Actions job:
name: OpenTaint
on: [push, pull_request]
jobs:
taint-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run OpenTaint
run: |
curl -fsSL https://opentaint.org/install.sh | bash
opentaint scan --output results.sarif .
- name: Upload SARIF to code scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
Now every pull request gets inline taint findings, and your once-authored rules guard the codebase on every commit — minutes of CPU, zero tokens. For the official, supported configuration, always check the docs.
11. Pro tips
- Start with Java/Spring. It has the deepest coverage today; other languages are on the roadmap.
- Make sure the project builds. Inter-procedural accuracy depends on type and dependency resolution — a broken build means a shallower graph.
- Model your libraries. If taint “disappears” inside a third-party call, add a pass-through approximation so the engine knows data flows through it.
- Tune sanitizers to cut noise. Declaring your real encoders/validators as sanitizers removes false positives cleanly.
- Commit your rules. Treat custom rules as code — they are your team’s accumulated security knowledge, replayable forever.
- Pin the Docker tag in CI for reproducible scans instead of latest.
Use only on the code you’re authorized to test
Run OpenTaint against repositories you own or are explicitly authorized to assess. Treat any findings — and the proof-of-concept artifacts agents may generate — as sensitive, and never paste secrets, live credentials, or client data into rules or issues.
12. Wrap-up
OpenTaint reframes the AI-vs-static-analysis debate: instead of paying a language model to re-read your code on every scan, you pay it once to understand a vulnerability, capture that understanding as a deterministic taint rule, and let a fast engine enforce it forever. You get the depth of an inter-procedural agent at the cost of a static analyzer — open source, self-hostable, and batteries-included.
Recap of the commands worth memorizing:
# install (pick one)
curl -fsSL https://opentaint.org/install.sh | bash
brew install --cask seqra/tap/opentaint
npm install -g @seqra/opentaint
# scan
opentaint scan # console
opentaint scan --output results.sarif . # SARIF report
opentaint scan --rules ./rules . # with custom rules
# docker (zero install)
docker run --rm -v $(pwd):/project -v $(pwd):/output \
ghcr.io/seqra/opentaint:latest \
opentaint scan --output /output/results.sarif /project
# AI agent skills
npx skills add https://github.com/seqra/opentaint
Next steps: read the official OpenTaint repository and documentation, run it on a real Spring app, and write your first custom rule. Then add it to your own AegisMind vault ai-security-tools/ so future-you can replay the workflow.
Thank you so much for reading
Like | Follow | Subscribe to the newsletter.
Catch us on
Website: https://www.techlatest.net/
Newsletter: https://substack.com/@techlatest
Twitter: https://twitter.com/TechlatestNet
LinkedIn: https://www.linkedin.com/in/techlatest-net/
YouTube:https://www.youtube.com/@techlatest_net/
Blogs: https://medium.com/@techlatest.net
Reddit Community: https://www.reddit.com/user/techlatest_net/






Top comments (0)