TaintFlow, a framework for JavaScript dynamic information flow analysis.
TaintFlow performs prior source code instrumentation which allows you to:
- Find DOM XSS vulnerabilities and unvalidated redirects with taint analysis.
- Improve your debugging experience since TaintFlow can observe any data flow in code and intercept it.
To install TaintFlow Transformer command line interface, you must have
Node.js with yarn
installed. Run:
yarn
PATH="$PATH:$(yarn bin)"
In the near future, after the initial release of TaintFlow, we will also
provide the following way to install it from the npm
global registry:
npm install --global @taintflow/cli
Transform script.js
with source code instrumentation and output to stdout
:
taintflow script.js
If you would like to transform the entire src
directory and output it to the
out
directory you may use -d
:
taintflow src -d out
There are many more options available, see taintflow --help
for more
information.
TaintFlow primarily consists of the following two components:
- Transformer is responsible for source code instrumentation.
- Runtime is responsible for runtime support of instrumented code.
In order to use TaintFlow features, you should firstly perform prior source code instrumentation with Transformer and then provide required Runtime dependency.
Runtime also provides extension point that can be used by another—maybe user-supplied—components which takes advantage of the source code instrumentation.
Given, for example, a JavaScript code like
const foo = bar();
TaintFlow transforms it into the following form:
const foo = taintflow.intercept({
type: "CallExpression",
callee: () => new taintflow.Identifier(() => bar),
arguments: () => [],
}).value;
Note: The Runtime namespace
taintflow
here should be exported globally for this code to work.
Of course, such instrumentation also implies significant slowdown (around 3-5 times), so it makes no sense to transform code for running in production environment.
By default, the intercept
function does nothing but evaluate intercepted
expressions in a standard way JavaScript behaves. However, it can be extended
to provide custom non-standard behaviour.
Example for brevity:
import * as taintflow from "@taintflow/runtime";
taintflow.extend((intercept) => (node) => {
// if we are calling some function from instrumented code,
// then just return "ha-ha!" instead
if (node.type === "CallExpression") {
return new taintflow.RValue("ha-ha!");
}
// otherwise, evaluate as usual
return intercept(node);
});
Obviously, such extensions can be chained to provide some complex behaviour.
To intercept and taint any data flow in the instrumented environment, you can
use Flow
:
import {Flow} from "@taintflow/runtime";
const hello = Flow.tainted("hello");
console.log(Flow.of(hello + "world").isTainted); // ⇒ true
You can also find some usage examples in the specification of Flow
.
Copyright © 2018—2019 Arthur Khashaev. See license for details.