feat: add security sink detection patterns for JavaScript/TypeScript
- Introduced `sink-detect.js` with various security sink detection patterns categorized by type (e.g., command injection, SQL injection, file operations). - Implemented functions to build a lookup map for fast sink detection and to match sink calls against known patterns. - Added `package-lock.json` for dependency management.
This commit is contained in:
@@ -183,4 +183,158 @@ public class NodeCallGraphExtractorTests
|
||||
Assert.Equal("/users/:id", ep.Route);
|
||||
Assert.Equal("GET", ep.Method);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BabelResultParser_ParsesSinks()
|
||||
{
|
||||
// Arrange
|
||||
var json = """
|
||||
{
|
||||
"module": "test",
|
||||
"nodes": [
|
||||
{
|
||||
"id": "js:test/handler.processRequest",
|
||||
"package": "test",
|
||||
"name": "processRequest"
|
||||
}
|
||||
],
|
||||
"edges": [],
|
||||
"entrypoints": [],
|
||||
"sinks": [
|
||||
{
|
||||
"caller": "js:test/handler.processRequest",
|
||||
"category": "command_injection",
|
||||
"method": "child_process.exec",
|
||||
"site": {
|
||||
"file": "handler.js",
|
||||
"line": 42,
|
||||
"column": 8
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
|
||||
// Act
|
||||
var result = BabelResultParser.Parse(json);
|
||||
|
||||
// Assert
|
||||
Assert.Single(result.Sinks);
|
||||
var sink = result.Sinks[0];
|
||||
Assert.Equal("js:test/handler.processRequest", sink.Caller);
|
||||
Assert.Equal("command_injection", sink.Category);
|
||||
Assert.Equal("child_process.exec", sink.Method);
|
||||
Assert.NotNull(sink.Site);
|
||||
Assert.Equal("handler.js", sink.Site.File);
|
||||
Assert.Equal(42, sink.Site.Line);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BabelResultParser_ParsesMultipleSinkCategories()
|
||||
{
|
||||
// Arrange
|
||||
var json = """
|
||||
{
|
||||
"module": "vulnerable-app",
|
||||
"nodes": [],
|
||||
"edges": [],
|
||||
"entrypoints": [],
|
||||
"sinks": [
|
||||
{
|
||||
"caller": "js:vulnerable-app/db.query",
|
||||
"category": "sql_injection",
|
||||
"method": "connection.query"
|
||||
},
|
||||
{
|
||||
"caller": "js:vulnerable-app/api.fetch",
|
||||
"category": "ssrf",
|
||||
"method": "fetch"
|
||||
},
|
||||
{
|
||||
"caller": "js:vulnerable-app/file.write",
|
||||
"category": "file_write",
|
||||
"method": "fs.writeFileSync"
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
|
||||
// Act
|
||||
var result = BabelResultParser.Parse(json);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, result.Sinks.Count);
|
||||
Assert.Contains(result.Sinks, s => s.Category == "sql_injection");
|
||||
Assert.Contains(result.Sinks, s => s.Category == "ssrf");
|
||||
Assert.Contains(result.Sinks, s => s.Category == "file_write");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BabelResultParser_ParsesEmptySinks()
|
||||
{
|
||||
// Arrange
|
||||
var json = """
|
||||
{
|
||||
"module": "safe-app",
|
||||
"nodes": [],
|
||||
"edges": [],
|
||||
"entrypoints": [],
|
||||
"sinks": []
|
||||
}
|
||||
""";
|
||||
|
||||
// Act
|
||||
var result = BabelResultParser.Parse(json);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result.Sinks);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BabelResultParser_ParsesMissingSinks()
|
||||
{
|
||||
// Arrange - sinks field omitted entirely
|
||||
var json = """
|
||||
{
|
||||
"module": "legacy-app",
|
||||
"nodes": [],
|
||||
"edges": [],
|
||||
"entrypoints": []
|
||||
}
|
||||
""";
|
||||
|
||||
// Act
|
||||
var result = BabelResultParser.Parse(json);
|
||||
|
||||
// Assert - should default to empty list
|
||||
Assert.Empty(result.Sinks);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BabelResultParser_ParsesSinkWithoutSite()
|
||||
{
|
||||
// Arrange
|
||||
var json = """
|
||||
{
|
||||
"module": "test",
|
||||
"nodes": [],
|
||||
"edges": [],
|
||||
"entrypoints": [],
|
||||
"sinks": [
|
||||
{
|
||||
"caller": "js:test/func",
|
||||
"category": "deserialization",
|
||||
"method": "eval"
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
|
||||
// Act
|
||||
var result = BabelResultParser.Parse(json);
|
||||
|
||||
// Assert
|
||||
Assert.Single(result.Sinks);
|
||||
Assert.Null(result.Sinks[0].Site);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user