Skip to content

bug(analyzer): taint is dropped on numeric values (int and boxed Integer), carried on reference types #388

Description

@DavidBakerEffendi

Hi — we maintain DataFlowBench, an open benchmark of dataflow/taint analyzers, and we recently added an OpenTaint adapter pinned to analyzer/2026.08.27.17eb0fe (adapter notes, PR). While adapting it we isolated one engine behavior that dominates its results, and it looked close enough to your recent "whole-object taint at a primitive position" work that it seemed worth reporting with a minimal repro.

Observed: for the same direct source→sink shape, varying only the value type, mode: taint rules report the String and Object variants and neither numeric one — int or boxed Integer:

static String string_src() { return "tainted"; }
static void string_sink(String v) { }
static void runString() { string_sink(string_src()); }   // reported

static int int_src() { return 1; }
static void int_sink(int v) { }
static void runInt() { int_sink(int_src()); }            // not reported

static Integer boxed_src() { return 1; }
static void boxed_sink(Integer v) { }
static void runBoxed() { boxed_sink(boxed_src()); }      // not reported

The rule-load trace shows all four rules registered, so it's not a rule-loading issue. Full retained evidence (fixture, rules, load trace, SARIF) is here, reproducible via scripts/probe-opentaint-value-kind.sh. Invocation: --project-kind=unknown, --debug-run-analysis-on-selected-entry-points=*, shipped models from opentaint-models.tar.gz.

If numeric taint is intentionally out of the threat model, a line of documentation would let us record it as a declared boundary rather than a measured miss.

Worth saying: on the reference-typed part of our corpus the engine did well — it correctly discriminates a depth-6 interprocedural relay pair that several engines miss at default call depths, plus recursion, closure capture, and two-level call context. Two smaller things we're happy to file separately if useful: a family of false positives where dynamically-selected heap locations (keyed map entries, computed members, function-valued fields) aren't kept separate, and two ergonomic asks (any version self-report in the analyzer jar, and a non-debug flag for all-methods entry points).


Note that I'm posting this via gh with Claude, who helped do the write-up.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions