no-directive-injection
Detects directive injection vulnerabilities in template systems. This rule is part of [`eslint-plugin-secure-coding`](https://www.npmjs.com/package/eslint-plugi
Keywords: directive injection, CWE-94, template injection, Angular, Vue, React, SSTI, XSS
Detects directive injection vulnerabilities in template systems. This rule is part of eslint-plugin-secure-coding.
💼 This rule is set to error in the recommended config.
Quick Summary
| Aspect | Details |
|---|---|
| CWE Reference | CWE-94 (Code Injection), CWE-96 (SSTI) |
| Severity | High (CVSS 8.8) |
| Auto-Fix | 💡 Suggestions available |
| Category | Injection Prevention |
Vulnerability and Risk
Vulnerability: Directive injection (specifically in frameworks like Angular or Vue) occurs when user-controlled attributes can modify the structure or behavior of the DOM in unexpected ways, potentially leading to Client-Side Template Injection (CSTI) or XSS.
Risk: Attackers can inject malicious directives to execute arbitrary JavaScript code within the victim's session, bypass framework security controls, or manipulate the application's view and logic.
Rule Details
Directive injection occurs when user input is used to inject malicious directives into template systems (Angular, Vue, React, etc.). Attackers can:
- Execute arbitrary JavaScript code
- Manipulate the DOM and steal user data
- Perform cross-site scripting (XSS) attacks
- Bypass Content Security Policy (CSP)
Why This Matters
| Issue | Impact | Solution |
|---|---|---|
| 💻 Code Execution | Full application compromise | Use static directives |
| 🎭 XSS | User session hijacking | Sanitize template input |
| 🔓 CSP Bypass | Security control evasion | Validate directive names |
Examples
❌ Incorrect
// Dynamic directive name from user input
const directive = userInput;
<div {...{[directive]: value}} />
// Template injection in Angular
const template = `<div ${userControlledDirective}>Content</div>`;
this.compile(template);
// dangerouslySetInnerHTML with user content
<div dangerouslySetInnerHTML={{__html: userHtml}} />
// Vue v-html with untrusted content
<div v-html="userContent"></div>✅ Correct
// Use hardcoded directive names
<div onClick={handleClick} />
// Sanitize HTML before rendering
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(userHtml)}} />
// Use trusted templates only
const template = trustedTemplates[templateId];
this.compile(template);
// Validate directive names against whitelist
const allowedDirectives = ['onClick', 'onChange', 'onSubmit'];
if (allowedDirectives.includes(directive)) {
<div {...{[directive]: value}} />
}Configuration
{
rules: {
'secure-coding/no-directive-injection': ['error', {
trustedDirectives: ['onClick', 'onChange', 'onSubmit'],
frameworks: ['react', 'angular', 'vue'],
allowDynamicInComponents: false
}]
}
}Options
| Option | Type | Default | Description |
|---|---|---|---|
trustedDirectives | string[] | [] | Allowed directive names |
userInputVariables | string[] | ['req', 'request', 'input'] | User input variable patterns |
frameworks | string[] | ['react', 'angular', 'vue'] | Frameworks to check |
allowDynamicInComponents | boolean | false | Allow dynamic directives in safe contexts |
Error Message Format
The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:
🔒 CWE-94 OWASP:A05 CVSS:9.8 | Code Injection detected | CRITICAL [SOC2,PCI-DSS,ISO27001]
Fix: Review and apply the recommended fix | https://owasp.org/Top10/A05_2021/Message Components
| Component | Purpose | Example |
|---|---|---|
| Risk Standards | Security benchmarks | CWE-94 OWASP:A05 CVSS:9.8 |
| Issue Description | Specific vulnerability | Code Injection detected |
| Severity & Compliance | Impact assessment | CRITICAL [SOC2,PCI-DSS,ISO27001] |
| Fix Instruction | Actionable remediation | Follow the remediation steps below |
| Technical Truth | Official reference | OWASP Top 10 |
Known False Negatives
The following patterns are not detected due to static analysis limitations:
Query from Variable
Why: Query strings from variables not traced.
// ❌ NOT DETECTED - Query from variable
const query = `SELECT * FROM users WHERE id = ${userId}`;
db.execute(query);Mitigation: Always use parameterized queries.
Custom Query Builders
Why: Custom ORM/query builders not recognized.
// ❌ NOT DETECTED - Custom builder
customQuery.where(userInput).execute();Mitigation: Review all query builder patterns.
Template Engines
Why: Template-based queries not analyzed.
// ❌ NOT DETECTED - Template
executeTemplate('query.sql', { userId });Mitigation: Validate all template variables.
Further Reading
- Angular Security - Angular security best practices
- React XSS Prevention - React security
- CWE-94 - Code injection documentation
- OWASP Injection - OWASP Top 10 Injection
Related Rules
no-unsanitized-html- XSS via innerHTMLdetect-eval-with-expression- Code injection via eval