Getting started
Requirements
- Node.js 22 or later. CI tests Node 22 and 24 on Linux and macOS.
- An ESM project. The package is
"type": "module"and has no CommonJS build.
Install
@js-recon/taintwire isn't published to npm yet. Until it is, build it from source and install the local copy:
git clone https://github.com/js-recon/taintwire.git
cd taintwire
npm install
npm run build
# in your project
npm install /path/to/taintwire
Your first graph
import * as taintwire from "@js-recon/taintwire";
const code = `
const q = location.hash.slice(1);
document.getElementById("out").innerHTML = q;
`;
// Parse `code` and load it into a new in-memory graph.
const graph = await taintwire.import(code, { filename: "app.js" });
// Find every assignment to `.innerHTML`.
const sinks = await graph.query(`
MATCH (a:AssignmentExpression)-[:SON {key: 'left'}]->(:MemberExpression)
-[:SON {key: 'property'}]->(:Identifier {name: 'innerHTML'})
RETURN a.id AS id, a.line AS line
`);
for (const { id, line } of sinks) console.log(line, await graph.code(id));
// 3 document.getElementById("out").innerHTML = q
await graph.close();
import is a reserved word, so you can't write import { import } from .... Use a namespace import as above, or rename it:
import { import as importCode, TaintGraph } from "@js-recon/taintwire";
More than one file
A graph can hold any number of files. Each needs a unique filename, and every node records which file it came from in its file column.
const graph = await taintwire.import(mainJs, { filename: "main.3f2a.js" });
await graph.add(chunkJs, "chunk.91bc.js");
await graph.query("MATCH (f:File) RETURN f.file AS file");
// [{ file: "main.3f2a.js" }, { file: "chunk.91bc.js" }]
Persisting graphs
Graphs are in-memory by default. There are two ways to get one onto disk:
// 1. Build straight into a LadybugDB file.
const graph = await taintwire.import(code, { dbPath: "graph.lbug" });
// 2. Build in memory, then write a copy out. Refuses to overwrite an existing path.
const mem = await taintwire.import(code);
await mem.save("graph.lbug");
Reopen a saved graph with TaintGraph.open(). You can keep adding files to it:
const graph = await taintwire.TaintGraph.open("graph.lbug");
await graph.add(moreCode, "late-chunk.js");
The file is a standard LadybugDB 0.21 database, so other Ladybug tools of the same version can open it too.
Next steps
- API reference: every export and method.
- Graph model: the node tables, columns and edges you query.
- Query cookbook: working queries and the Cypher gotchas specific to this graph.
- Parsers:
cs-mastagainstbabel, and what to do when parsing fails.