mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-24 20:28:06 +02:00
Phase 1 (#33)
* chore: Exclude CLAUDE.md from Cargo.toml * feat: add callgraph module and integrate into main analysis flow * feat: enhance CLI with new severity filtering and analysis modes * feat: update CHANGELOG with recent enhancements and fixes to severity filtering and output handling * feat: implement state-model dataflow analysis for resource lifecycle and auth state * feat: enhance diagnostic output formatting and add evidence structure * feat: implement attack surface ranking for diagnostics with scoring and sorting * feat: add comprehensive documentation for installation, usage, and rules reference * feat: add multiple language support for command execution and evaluation endpoints * feat: implement inline suppression for findings using `nyx:ignore` comments * feat: add confidence levels to AST patterns and update output structure * feat: implement low-noise prioritization system with category filtering, rollup grouping, and configurable budgets * feat: bump version to 0.4.0 and update changelog with new features and improvements * feat: add dead code allowances to various functions in mod.rs and real_world_tests.rs
This commit is contained in:
parent
19b578c5c4
commit
1bbe4b1cfb
456 changed files with 25628 additions and 1228 deletions
60
tests/fixtures/real_world/javascript/mixed/express_auth_cmdi.expect.json
vendored
Normal file
60
tests/fixtures/real_world/javascript/mixed/express_auth_cmdi.expect.json
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"description": "Express route with command injection: one without auth check, one with auth check. Taint flows in both cases since auth does not sanitize the input.",
|
||||
"tags": [
|
||||
"mixed",
|
||||
"taint",
|
||||
"cfg",
|
||||
"cmdi",
|
||||
"auth",
|
||||
"express"
|
||||
],
|
||||
"modes": [
|
||||
"full"
|
||||
],
|
||||
"expected": [
|
||||
{
|
||||
"rule_id": "taint-unsanitised-flow",
|
||||
"severity": null,
|
||||
"must_match": true,
|
||||
"line_range": [
|
||||
9,
|
||||
14
|
||||
],
|
||||
"evidence_contains": [],
|
||||
"notes": "req.query.branch flows into child_process.exec in unauthed /deploy route"
|
||||
},
|
||||
{
|
||||
"rule_id": "taint-unsanitised-flow",
|
||||
"severity": null,
|
||||
"must_match": true,
|
||||
"line_range": [
|
||||
21,
|
||||
26
|
||||
],
|
||||
"evidence_contains": [],
|
||||
"notes": "req.query.branch flows into child_process.exec in authed /deploy-safe route; auth check does not sanitize"
|
||||
},
|
||||
{
|
||||
"rule_id": "cfg-auth-gap",
|
||||
"severity": null,
|
||||
"must_match": false,
|
||||
"line_range": [
|
||||
8,
|
||||
17
|
||||
],
|
||||
"evidence_contains": [],
|
||||
"notes": "No auth check before child_process.exec in /deploy handler"
|
||||
},
|
||||
{
|
||||
"rule_id": "cfg-unguarded-sink",
|
||||
"severity": null,
|
||||
"must_match": false,
|
||||
"line_range": [
|
||||
10,
|
||||
14
|
||||
],
|
||||
"evidence_contains": [],
|
||||
"notes": "child_process.exec called without input validation guard"
|
||||
}
|
||||
]
|
||||
}
|
||||
26
tests/fixtures/real_world/javascript/mixed/express_auth_cmdi.js
vendored
Normal file
26
tests/fixtures/real_world/javascript/mixed/express_auth_cmdi.js
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
var express = require('express');
|
||||
var child_process = require('child_process');
|
||||
var app = express();
|
||||
|
||||
function isAdmin(req) {
|
||||
return req.headers['x-admin'] === 'true';
|
||||
}
|
||||
|
||||
// Missing auth check before dangerous operation
|
||||
app.get('/deploy', function(req, res) {
|
||||
var branch = req.query.branch;
|
||||
child_process.exec('git checkout ' + branch, function(err, stdout) {
|
||||
res.send(stdout);
|
||||
});
|
||||
});
|
||||
|
||||
// Has auth check but taint still flows
|
||||
app.get('/deploy-safe', function(req, res) {
|
||||
if (!isAdmin(req)) {
|
||||
return res.status(403).send('Forbidden');
|
||||
}
|
||||
var branch = req.query.branch;
|
||||
child_process.exec('git checkout ' + branch, function(err, stdout) {
|
||||
res.send(stdout);
|
||||
});
|
||||
});
|
||||
49
tests/fixtures/real_world/javascript/mixed/taint_through_state.expect.json
vendored
Normal file
49
tests/fixtures/real_world/javascript/mixed/taint_through_state.expect.json
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"description": "Combined taint and state: req.body.name used in file path, fd leaks on early return, and a separate command injection via req.query.cmd.",
|
||||
"tags": [
|
||||
"mixed",
|
||||
"taint",
|
||||
"state",
|
||||
"resource-leak",
|
||||
"cmdi",
|
||||
"express"
|
||||
],
|
||||
"modes": [
|
||||
"full"
|
||||
],
|
||||
"expected": [
|
||||
{
|
||||
"rule_id": "taint-unsanitised-flow",
|
||||
"severity": null,
|
||||
"must_match": true,
|
||||
"line_range": [
|
||||
18,
|
||||
23
|
||||
],
|
||||
"evidence_contains": [],
|
||||
"notes": "req.query.cmd flows directly into child_process.exec"
|
||||
},
|
||||
{
|
||||
"rule_id": "taint-unsanitised-flow",
|
||||
"severity": null,
|
||||
"must_match": false,
|
||||
"line_range": [
|
||||
5,
|
||||
11
|
||||
],
|
||||
"evidence_contains": [],
|
||||
"notes": "req.body.name flows into fs.openSync path but fs.openSync is not a recognized taint sink"
|
||||
},
|
||||
{
|
||||
"rule_id": "state-resource-leak-possible",
|
||||
"severity": null,
|
||||
"must_match": false,
|
||||
"line_range": [
|
||||
7,
|
||||
15
|
||||
],
|
||||
"evidence_contains": [],
|
||||
"notes": "fd from fs.openSync leaks when early return fires at line 13; scanner may not track JS fd lifecycle"
|
||||
}
|
||||
]
|
||||
}
|
||||
24
tests/fixtures/real_world/javascript/mixed/taint_through_state.js
vendored
Normal file
24
tests/fixtures/real_world/javascript/mixed/taint_through_state.js
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
var express = require('express');
|
||||
var fs = require('fs');
|
||||
var child_process = require('child_process');
|
||||
var app = express();
|
||||
|
||||
app.post('/upload', function(req, res) {
|
||||
var filename = req.body.name;
|
||||
var content = req.body.data;
|
||||
var fd = fs.openSync('/tmp/' + filename, 'w');
|
||||
fs.writeSync(fd, content);
|
||||
// fd leaks on early return
|
||||
if (content.length > 1000000) {
|
||||
return res.status(413).send('Too large');
|
||||
}
|
||||
fs.closeSync(fd);
|
||||
res.send('OK');
|
||||
});
|
||||
|
||||
app.get('/run', function(req, res) {
|
||||
var cmd = req.query.cmd;
|
||||
child_process.exec(cmd, function(err, stdout) {
|
||||
res.send(stdout);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue