{
  "rule": {
    "id": "S023",
    "name": "Use output encoding when building dynamic JavaScript/JSON",
    "description": "Prevent JavaScript and JSON injection by applying proper output encoding when dynamically building JavaScript content or JSON data. Detects unsafe eval(), new Function(), string concatenation for JS building, template literals with unescaped user input, and JSON.stringify in HTML context without proper escaping.",
    "category": "security",
    "severity": "error",
    "languages": ["typescript", "javascript", "dart"],
    "frameworks": ["express", "nestjs", "node", "react", "vue", "angular", "next"],
    "version": "2.0.0",
    "status": "stable",
    "tags": ["security", "json", "javascript", "injection", "xss", "owasp", "eval", "output-encoding"],
    "references": [
      "https://owasp.org/www-community/vulnerabilities/JSON_Injection",
      "https://cheatsheetseries.owasp.org/cheatsheets/Injection_Prevention_Cheat_Sheet.html",
      "https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html",
      "https://portswigger.net/web-security/dom-based/json-injection",
      "https://cwe.mitre.org/data/definitions/94.html",
      "https://cwe.mitre.org/data/definitions/79.html"
    ]
  },
  "configuration": {
    "checkEval": true,
    "checkNewFunction": true,
    "checkStringConcatenation": true,
    "checkTemplateLiterals": true,
    "checkJsonParse": true,
    "checkJsonStringifyInHtml": true,
    "checkInlineEventHandlers": true,
    "dangerousCharacters": ["\\", "'", "\"", "<", ">", "&", "\n", "\r"],
    "userInputSources": [
      "localStorage",
      "sessionStorage",
      "window.location",
      "location.search",
      "location.hash",
      "location.href",
      "URLSearchParams",
      "req.body",
      "req.query",
      "req.params",
      "request.body",
      "request.query",
      "document.cookie",
      "window.name",
      "postMessage",
      "fetch",
      "axios",
      "getElementById",
      "querySelector",
      "formData",
      "event.data"
    ],
    "dangerousPatterns": {
      "evalWithUserData": [
        "eval\\s*\\(",
        "new\\s+Function\\s*\\("
      ],
      "stringConcatenationJS": [
        "var\\s+\\w+\\s*=\\s*['\"].*['\"]\\s*\\+",
        "let\\s+\\w+\\s*=\\s*['\"].*['\"]\\s*\\+",
        "const\\s+\\w+\\s*=\\s*['\"].*['\"]\\s*\\+"
      ],
      "inlineEventHandlers": [
        "on\\w+\\s*=\\s*['\"].*\\$\\{",
        "on\\w+\\s*=\\s*['\"].*\\+",
        "setAttribute\\s*\\(\\s*['\"]on\\w+"
      ],
      "unsafeTemplateLiterals": [
        "`.*\\$\\{.*\\}.*`"
      ],
      "scriptTagInjection": [
        "</script>",
        "<script",
        "javascript:"
      ]
    },
    "htmlContextPatterns": [
      "innerHTML",
      "outerHTML",
      "insertAdjacentHTML",
      "document.write",
      "document.writeln",
      ".html(",
      "<script",
      "</script>",
      "dangerouslySetInnerHTML"
    ],
    "safeEncodingFunctions": [
      "encodeURIComponent",
      "encodeURI",
      "escape",
      "escapeHtml",
      "sanitize",
      "DOMPurify.sanitize",
      "xss",
      "encode",
      "htmlEncode",
      "jsEncode",
      "textContent"
    ],
    "validationPatterns": [
      "try",
      "catch",
      "typeof",
      "instanceof",
      "validate",
      "check",
      "isValid",
      "sanitize",
      "escape",
      "filter",
      "JSON.parse",
      "JSON.stringify"
    ]
  },
  "examples": {
    "violations": [
      {
        "description": "Using eval() with user data",
        "code": "eval('var x = ' + userInput);"
      },
      {
        "description": "Using new Function() with user data",
        "code": "const fn = new Function('return ' + userInput);"
      },
      {
        "description": "String concatenation to build JavaScript",
        "code": "var code = 'var x = \"' + userInput + '\"';"
      },
      {
        "description": "Template literals with unescaped user input in JS context",
        "code": "element.innerHTML = `<div onclick=\"handleClick('${userInput}')\">Click</div>`;"
      },
      {
        "description": "Inline event handlers with user data",
        "code": "element.setAttribute('onclick', 'process(\"' + userInput + '\")');"
      },
      {
        "description": "JSON.stringify in HTML context without escaping </script>",
        "code": "document.write('<script>var data = ' + JSON.stringify(userInput) + '</script>');"
      }
    ],
    "fixes": [
      {
        "description": "Use JSON.parse instead of eval for JSON",
        "code": "const data = JSON.parse(jsonString);"
      },
      {
        "description": "Encode data before inserting into JavaScript strings",
        "code": "const safeInput = encodeURIComponent(userInput);\nelement.dataset.value = safeInput;"
      },
      {
        "description": "Use textContent instead of innerHTML for text",
        "code": "element.textContent = userInput;"
      },
      {
        "description": "Escape </script> sequences when embedding JSON in HTML",
        "code": "const safeJson = JSON.stringify(data).replace(/<\\/script/gi, '<\\\\/script');\ndocument.write('<script>var data = ' + safeJson + '<\\/script>');"
      },
      {
        "description": "Use data attributes and event listeners instead of inline handlers",
        "code": "element.dataset.value = userInput;\nelement.addEventListener('click', () => handleClick(element.dataset.value));"
      }
    ]
  },
  "testing": {
    "testCases": [
      {
        "name": "eval_with_user_input",
        "type": "violation",
        "description": "Using eval() to execute user-provided data"
      },
      {
        "name": "new_function_with_user_input",
        "type": "violation",
        "description": "Using new Function() with user-provided data"
      },
      {
        "name": "string_concatenation_js_building",
        "type": "violation",
        "description": "Building JavaScript code via string concatenation"
      },
      {
        "name": "template_literal_unescaped",
        "type": "violation",
        "description": "Template literal with unescaped user input in JS context"
      },
      {
        "name": "inline_event_handler_user_data",
        "type": "violation",
        "description": "Inline event handler with user data"
      },
      {
        "name": "json_stringify_html_no_escape",
        "type": "violation",
        "description": "JSON.stringify in HTML without escaping </script>"
      },
      {
        "name": "safe_json_parse",
        "type": "clean",
        "description": "Using JSON.parse with proper error handling"
      },
      {
        "name": "safe_text_content",
        "type": "clean",
        "description": "Using textContent for user data"
      }
    ]
  },
  "performance": {
    "complexity": "O(n)",
    "description": "Linear complexity based on number of JavaScript/JSON operations in source code"
  },
  "owaspMapping": {
    "category": "A03:2021 – Injection",
    "subcategories": [
      "A07:2021 – Cross-Site Scripting (XSS)"
    ],
    "description": "Validates that dynamic JavaScript and JSON construction uses proper output encoding to prevent injection attacks and XSS vulnerabilities"
  }
}
