Sample Security Audit Report

Static Application Security Testing

Multi-language SAST covering Java, PHP, Python, MERN, and OWASP LLM Top 10 with 200+ rules and 80+ dependency CVEs. 212 findings generated by the open-source scanner.

Scanner
java_scanner.py v4.0.0
Mode
Static Analysis (Java)
Scan Date
2026-03-31

Finding Summary

59
Critical
105
High
44
Medium
4
Low
0
Info
0
/ 100

Security Posture F — Critical

59 critical findings require immediate attention. 105 high-severity issues compound the risk. 44 medium-severity findings should be addressed in the next sprint. 4 low-severity items are informational or best-practice recommendations.

Findings by Category

Detailed Findings

Showing 212 of 212

Compliance Mapping

OWASP Top 10 2021
CWE
SANS Top 25
`);", "cwe": "CWE-79"}, {"rule_id": "MERN-SSRF-001", "name": "axios/fetch/node-fetch with user-controlled URL", "category": "Server-Side Request Forgery (SSRF)", "severity": "HIGH", "description": "Making HTTP requests to URLs derived from user input enables SSRF. Attackers can reach internal services, cloud metadata endpoints (169.254.169.254), and internal APIs.", "recommendation": "Validate and allowlist target URLs/hostnames. Block requests to private IP ranges and cloud metadata addresses. Use a dedicated HTTP proxy with egress controls.", "source": "tests\\samples\\vulnerable_mern.js", "context": "const response = await axios.get(req.body.url);", "cwe": "CWE-918"}, {"rule_id": "MERN-REDIR-001", "name": "res.redirect() with user-controlled URL", "category": "Open Redirect", "severity": "MEDIUM", "description": "Redirecting to a URL derived from user input enables open redirect attacks used for phishing and OAuth token theft.", "recommendation": "Validate redirect targets against a strict allowlist of permitted hostnames. Reject absolute URLs or enforce same-origin redirects.", "source": "tests\\samples\\vulnerable_mern.js", "context": "res.redirect(req.query.url);", "cwe": "CWE-601"}, {"rule_id": "MERN-JWT-001", "name": "JWT signed with hardcoded or weak secret", "category": "Broken Authentication", "severity": "CRITICAL", "description": "A short or guessable JWT secret allows attackers to forge tokens and impersonate any user, including admins.", "recommendation": "Generate a cryptographically random secret of at least 256 bits. Store it in an environment variable—never hardcode it.", "source": "tests\\samples\\vulnerable_mern.js", "context": "const token = jwt.sign({ id: user._id, role: user.role }, 'mysecret');", "cwe": "CWE-330"}, {"rule_id": "MERN-JWT-002", "name": "JWT verification with algorithms: ['none']", "category": "Broken Authentication", "severity": "CRITICAL", "description": "Allowing the 'none' algorithm in JWT verification lets attackers strip the signature and forge arbitrary tokens (CVE-2015-9235).", "recommendation": "Explicitly specify only HMAC or RSA algorithms: { algorithms: ['HS256'] }. Never allow 'none'.", "source": "tests\\samples\\vulnerable_mern.js", "context": "const decoded = jwt.verify(token, jwtSecret, { algorithms: ['none', 'HS256'] });", "cwe": "CWE-347"}, {"rule_id": "MERN-JWT-003", "name": "JWT verified without expiry check", "category": "Broken Authentication", "severity": "MEDIUM", "description": "Calling jwt.verify() with only two arguments skips options like maxAge/expiresIn enforcement if not embedded in the token.", "recommendation": "Pass a third options argument: jwt.verify(token, secret, { algorithms: ['HS256'], maxAge: '1h' }).", "source": "tests\\samples\\vulnerable_mern.js", "context": "const decoded2 = jwt.verify(token, jwtSecret);", "cwe": "CWE-613"}, {"rule_id": "MERN-PROTO-001", "name": "lodash _.merge() / _.defaultsDeep() with req.body", "category": "Prototype Pollution", "severity": "HIGH", "description": "lodash _.merge() and _.defaultsDeep() recursively merge properties including __proto__. Supplying {\"__proto__\":{\"admin\":true}} pollutes Object.prototype and can escalate privileges or crash the server.", "recommendation": "Use JSON.parse(JSON.stringify(input)) to deep-clone before merging, or validate input against a strict schema. Upgrade lodash ≥ 4.17.21.", "source": "tests\\samples\\vulnerable_mern.js", "context": "_.merge(config, req.body);", "cwe": "CWE-1321"}, {"rule_id": "MERN-PROTO-002", "name": "Object.assign() with user-controlled source", "category": "Prototype Pollution", "severity": "MEDIUM", "description": "Object.assign() copies enumerable own properties. A source object with __proto__ manipulation can pollute prototypes in older Node.js.", "recommendation": "Validate and sanitize user-supplied objects before merging. Use a schema validator (Joi, Zod).", "source": "tests\\samples\\vulnerable_mern.js", "context": "const result = Object.assign({}, req.body);", "cwe": "CWE-1321"}, {"rule_id": "MERN-SEC-001", "name": "Hardcoded JWT / session secret in source", "category": "Hardcoded Credentials", "severity": "CRITICAL", "description": "A hardcoded JWT or session secret is exposed to anyone with read access to the source, enabling token forgery and session hijacking.", "recommendation": "Load secrets from environment variables via process.env. Use a secrets manager (Vault, AWS SSM).", "source": "tests\\samples\\vulnerable_mern.js", "context": "const jwtSecret = 'mysecret';", "cwe": "CWE-798"}, {"rule_id": "MERN-SEC-002", "name": "MongoDB connection string with embedded credentials", "category": "Hardcoded Credentials", "severity": "HIGH", "description": "Embedding MongoDB credentials directly in the connection URI exposes them in source code, logs, and error messages.", "recommendation": "Store the connection string in an environment variable. Use MongoDB Atlas credential rotation.", "source": "tests\\samples\\vulnerable_mern.js", "context": "mongoose.connect('mongodb://admin:SuperSecret123@localhost:27017/myapp');", "cwe": "CWE-798"}, {"rule_id": "MERN-SEC-003", "name": "Hardcoded API key or token literal", "category": "Hardcoded Credentials", "severity": "HIGH", "description": "Hardcoded API keys or tokens can be extracted from source or compiled bundles.", "recommendation": "Load secrets from environment variables. Rotate any key that was ever committed to source control.", "source": "tests\\samples\\vulnerable_mern.js", "context": "const apiKey = 'EXAMPLE_API_KEY_1234567890abcdef1234567890abcdef';", "cwe": "CWE-798"}, {"rule_id": "MERN-SEC-003", "name": "Hardcoded API key or token literal", "category": "Hardcoded Credentials", "severity": "HIGH", "description": "Hardcoded API keys or tokens can be extracted from source or compiled bundles.", "recommendation": "Load secrets from environment variables. Rotate any key that was ever committed to source control.", "source": "tests\\samples\\vulnerable_mern.js", "context": "const accessToken = 'EXAMPLE_ACCESS_TOKEN_abcdefghijklmnopqrstuvwxyz1234';", "cwe": "CWE-798"}, {"rule_id": "MERN-DESER-001", "name": "node-serialize unserialize() with user input – RCE", "category": "Insecure Deserialization", "severity": "CRITICAL", "description": "node-serialize's unserialize() executes Immediately Invoked Function Expressions (IIFEs) embedded in serialized data, enabling unauthenticated RCE (CVE-2017-5941).", "recommendation": "Never deserialize user-supplied data with node-serialize. Use JSON.parse() for data exchange.", "source": "tests\\samples\\vulnerable_mern.js", "context": "const obj = serialize.unserialize(req.body.data);", "cwe": "CWE-502"}, {"rule_id": "MERN-DESER-002", "name": "YAML.load() without safeLoad in Node.js", "category": "Insecure Deserialization", "severity": "CRITICAL", "description": "js-yaml's YAML.load() in DEFAULT_FULL_SCHEMA mode instantiates arbitrary JavaScript types, including functions, enabling RCE.", "recommendation": "Use YAML.safeLoad() (js-yaml ≤ 3.x) or yaml.load() with { schema: FAILSAFE_SCHEMA } (js-yaml 4+).", "source": "tests\\samples\\vulnerable_mern.js", "context": "const config = yaml.load(req.body.config);", "cwe": "CWE-502"}, {"rule_id": "MERN-CONF-001", "name": "CORS configured with wildcard origin (*)", "category": "Security Misconfiguration", "severity": "MEDIUM", "description": "Allowing all origins with CORS (*) allows any website to make authenticated cross-origin requests to this API, enabling CSRF and data theft.", "recommendation": "Restrict CORS to specific trusted origins. Never use '*' with credentials:true.", "source": "tests\\samples\\vulnerable_mern.js", "context": "res.header('Access-Control-Allow-Origin', '*');", "cwe": "CWE-942"}, {"rule_id": "MERN-CONF-003", "name": "Helmet.js not used (missing security headers)", "category": "Security Misconfiguration", "severity": "LOW", "description": "Express apps without helmet() lack security headers: Content-Security-Policy, X-Frame-Options, X-XSS-Protection, etc.", "recommendation": "Add helmet() as the first middleware: app.use(require('helmet')()).", "source": "tests\\samples\\vulnerable_mern.js", "context": "const app = express();", "cwe": "CWE-16"}, {"rule_id": "MERN-REDOS-001", "name": "Complex nested quantifiers in regex pattern", "category": "Regular Expression DoS (ReDoS)", "severity": "MEDIUM", "description": "Constructing a RegExp from user-supplied input and running it against long strings can trigger catastrophic backtracking (ReDoS), blocking the Node.js event loop.", "recommendation": "Never build RegExp from user input. Use a safe-regex library to audit all regex patterns.", "source": "tests\\samples\\vulnerable_mern.js", "context": "const pattern = new RegExp(req.query.pattern);", "cwe": "CWE-1333"}]; /* ================================================================ RENDER ================================================================ */ const SEV_ORDER = {CRITICAL:0,HIGH:1,MEDIUM:2,LOW:3,INFO:4}; const SEV_COLORS = {CRITICAL:'var(--sev-critical)',HIGH:'var(--sev-high)',MEDIUM:'var(--sev-medium)',LOW:'var(--sev-low)',INFO:'var(--sev-info)'}; // Category chart (function renderCatChart(){ const cats = {}; FINDINGS.forEach(f => { cats[f.category] = (cats[f.category]||0) + 1 }); const sorted = Object.entries(cats).sort((a,b) => b[1]-a[1]); if(!sorted.length) return; const max = sorted[0][1]; const barColors = ['#EF4444','#F59E0B','#3B82F6','#8B5CF6','#22C55E','#EC4899','#06B6D4','#F97316','#14B8A6','#A855F7']; const container = document.getElementById('catChart'); container.innerHTML = sorted.map(([cat, count], i) => { const pct = Math.round((count / max) * 100); return `
${cat}
${count}
`; }).join(''); })(); // Populate category filter (function populateCatFilter(){ const cats = [...new Set(FINDINGS.map(f=>f.category))].sort(); const sel = document.getElementById('catFilter'); cats.forEach(c => { const o = document.createElement('option'); o.value = c; o.textContent = c; sel.appendChild(o) }); })(); // Render findings function renderFindings(list){ const container = document.getElementById('findingsContainer'); if(!list.length){ container.innerHTML = '

No findings match the current filters.

'; return; } container.innerHTML = list.map((f, i) => `
${f.severity} ${f.rule_id} ${escHtml(f.name)}
Issue
${escHtml(f.description)}
Recommendation
${escHtml(f.recommendation)}
${f.context ? `
Context
${escHtml(f.context)}
` : ''} ${f.source ? `
Source
${escHtml(f.source)}
` : ''} ${f.cwe ? `
Weakness
${f.cwe}
` : ''}
Category
${escHtml(f.category)}
`).join(''); } function escHtml(s){ if(!s) return ''; return String(s).replace(/&/g,'&').replace(//g,'>') } // Initial render renderFindings(FINDINGS); // Filters function applyFilters(){ const sev = document.getElementById('sevFilter').value; const cat = document.getElementById('catFilter').value; const q = document.getElementById('searchFilter').value.toLowerCase(); // Reset sev card highlights document.querySelectorAll('.sev-card').forEach(c => c.classList.remove('active')); if(sev) document.querySelector(`.sev-card[data-sev="${sev}"]`)?.classList.add('active'); const filtered = FINDINGS.filter(f => { if(sev && f.severity !== sev) return false; if(cat && f.category !== cat) return false; if(q && !((f.rule_id||'')+' '+(f.name||'')+' '+(f.description||'')+' '+(f.context||'')+' '+(f.cwe||'')+' '+(f.category||'')).toLowerCase().includes(q)) return false; return true; }); renderFindings(filtered); document.getElementById('filterCount').textContent = `Showing ${filtered.length} of ${FINDINGS.length}`; } function filterBySev(sev){ const sel = document.getElementById('sevFilter'); sel.value = sel.value === sev ? '' : sev; applyFilters(); document.querySelector('.findings-section').scrollIntoView({behavior:'smooth'}); }