cd /news/ai-tools/sentinel-ir-0-2-1-when-eval-hides-be… · home › topics › ai-tools › article
[ARTICLE · art-161883] src=dev.to ↗ pub= topic=ai-tools verified=true sentiment=↑ positive

Sentinel-IR 0.2.1: When "eval" Hides Behind an Alias

A developer released Sentinel-IR 0.2.1, an AST-based static analysis layer that uses Tree-sitter to extract structured facts from JavaScript and TypeScript so AI systems can reason about code without ingesting full source files. The update adds six regression tests and improves alias tracking for indirect eval calls across switch fallthrough and try/catch control flow, aiming to catch real dangerous paths while avoiding false positives when control flow makes them impossible.

by read5 min views4 publishedNov 1, 2026

Sentinel-IR 0.2.1

https://www.npmjs.com/package/sentinel-ir/v/0.2.1

Thanks for support..

Release: "Sentinel-IR-MCP v0.2.2 on GitLab" (https://gitlab.com/jakubrojicek11/sentinel-ir-mcp/-/tree/v0.2.2?ref_type=tags)

Package: "sentinel-ir-mcp@0.2.2 on npm" (https://www.npmjs.com/package/sentinel-ir-mcp/v/0.2.2)

A focused improvement in AST-based analysis, six regression tests, and a closer look at two tricky JavaScript control-flow paths.

The first 30 seconds

What happens when dangerous code execution does not look like "eval()"?

Sometimes JavaScript stores "eval" in another variable and calls that variable later. A static analyzer that only looks for direct calls can miss the connection.

In Sentinel-IR 0.2.1, I focused on two situations where this can happen: "switch" fallthrough and "try/catch" control flow.

The update adds six regression tests. The goal is simple: detect the dangerous path when it is real, but avoid raising an alarm when the control flow makes that path impossible.

No magic. Just better reasoning about code.

Part 1: The 3-minute explanation for everyone

First, what does Sentinel-IR actually do?

Sentinel-IR is a small structural analysis layer for code.

Instead of sending an entire JavaScript or TypeScript source file to an AI model, it extracts structured facts using Tree-sitter.

Think of it as giving the AI a map instead of handing it an entire city.

The resulting information can include:

This makes it easier for another system to reason about code without treating every line of source as equally important.

Project: "Sentinel-IR on GitLab" (https://gitlab.com/jakubrojicek11/sentinel-ir)

The problem: a function can have another name

Consider this:

const execute = eval;

execute("1 + 1");

A beginner might look for the word "eval" and assume the problem is easy.

But the function is being called through another variable.

That variable is an alias. The analyzer must understand what it refers to, not just what its name looks like.

And JavaScript has a few places where this gets complicated.

Problem one: switch fallthrough

Look at this example:

let execute = (value) => value;

switch (mode) {

case 0:

    execute = eval;
case 1:
    execute("1 + 1");
    break;

}

Notice something?

There is no "break" after "case 0".

JavaScript continues into the next case. The alias assigned in the first case can therefore be used in the second one.

A simple analyzer may treat these cases as completely separate blocks and miss the connection.

Think of "break" as a stop sign. Without it, the baton keeps moving.

Problem two: try/catch

Another example:

try {

execute = eval;

throw new Error("Something happened");

} catch (error) {

execute("1 + 1");

}

The alias is assigned before the exception.

When the exception moves execution into "catch", the analyzer needs to understand that the assignment can reach the code there.

But the opposite matters too.

An assignment that happens after an unconditional throw cannot influence the catch block. An assignment in a try block without a later explicit throw should not automatically make the catch block look dangerous either.

This is where false positives and false negatives start competing for attention.

What changed in 0.2.1?

The update improves those two control-flow situations.

It adds checks for:

The result should be more accurate detection, not simply more things marked as dangerous.

Part 2: The developer section

What changed inside the AST analysis?

The important change is not a new search for the word "eval".

It is more accurate tracking of alias assignments and their visibility across control-flow paths.

The implementation contains dedicated helpers for:

A parser detail worth mentioning

During the investigation, I encountered a subtle issue with Tree-sitter node wrappers.

Two JavaScript objects can represent the same logical AST node without being the same object reference.

Comparing them using:

nodeA === nodeB

is therefore not reliable for this kind of comparison.

The updated implementation compares the node type and source boundaries instead:

function evalAliasSameNode(a, b) {

return Boolean(

    a &&

    b &&

    a.type === b.type &&

    a.startIndex === b.startIndex &&

    a.endIndex === b.endIndex

);

}

This gives the analysis a stable way to recognize the same logical node.

Source: "AST implementation in v0.2.1" (https://gitlab.com/jakubrojicek11/sentinel-ir/-/blob/v0.2.1/src/ast-facts.js)

The six regression tests

The six new cases are documented in the release test suite.

Test scenario| Expected result

Alias passes through switch fallthrough| Critical

"break" blocks the alias flow| Low

Later case overwrites the alias| Low

Alias assigned before throw reaches catch| Critical

Throw happens before assignment| Low

No later explicit throw in try| Low

The tests verify more than a boolean detection result.

They also check that:

Here is the core shape of the regression assertions:

const facts = AstFacts.extract(source);

assert.equal(facts.ast, true);

assert.equal(

Boolean(facts.operations.dynamicEval),

expected

);

assert.equal(

AstFacts.riskOf(facts),

expected ? "critical" : "low"

);

assert.equal(

facts.riskSignals.some(

    signal => signal.signal === "dynamic_code"

),

expected

);

Full tests: "test/ast-facts.test.js, v0.2.1" (https://gitlab.com/jakubrojicek11/sentinel-ir/-/blob/v0.2.1/test/ast-facts.test.js)

Validation results

The release work was tested locally before tagging.

Validation| Result

Existing tests| 100 passed

New regression tests| 6 passed

Complete test suite| 106/106 passed

Packaged tarball smoke checks| 7/7 passed

The package was also installed into a clean consumer project for a separate smoke test.

That matters because a successful source test does not automatically prove that the packaged artifact works after installation.

What this does not mean

Sentinel-IR is not a complete JavaScript interpreter.

Its control-flow analysis is a conservative approximation, not a full simulation of every possible runtime path. It works with structural facts extracted from source code and has documented limitations.

It should be treated as an analysis component, not as a guarantee that dangerous code will always be detected.

That distinction matters, especially when an AI agent uses the output to make decisions.

Final thoughts

Version 0.2.1 is a focused release.

It does not introduce a new language or a completely new architecture. It improves one important part of the existing analyzer: understanding when an alias to dynamic code execution can actually reach a call site.

Sometimes progress in static analysis is not about detecting more patterns.

Sometimes it is about understanding why two pieces of code are connected, and when they are not.

And occasionally, the biggest bug is hiding behind a missing "break".

Sentinel-IR 0.2.1 is released.

Project links

Built and tested as an independent project. Feedback, edge cases and reproducible examples are welcome.

── more in #ai-tools 4 stories · sorted by recency
── more on @sentinel-ir 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/sentinel-ir-0-2-1-wh…] indexed:0 read:5min 2026-11-01 · —