{"record":{"id":"a6c42e8f6726512b","repo":"davila7/claude-code-templates","slug":"sem-e018","errorCode":"SEM_E018","errorMessage":"onerror handler detected (XSS risk)","messagePattern":"onerror handler detected \\(XSS risk\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli-tool/src/validation/validators/SemanticValidator.js","lineNumber":290,"sourceCode":"          path,\n          severity,\n          matches: contexts.length,\n          examples: contexts.slice(0, 3)\n        });\n      }\n    }\n  }\n\n  /**\n   * Check for HTML/Script injection attempts\n   */\n  checkHtmlInjection(content, path) {\n    const dangerousTags = [\n      { tag: '<script', code: 'SEM_E014', message: '<script> tag detected (XSS risk)' },\n      { tag: '<iframe', code: 'SEM_E015', message: '<iframe> tag detected (injection risk)' },\n      { tag: 'javascript:', code: 'SEM_E016', message: 'javascript: protocol detected (XSS risk)' },\n      { tag: 'onclick=', code: 'SEM_E017', message: 'Inline event handler detected (XSS risk)' },\n      { tag: 'onerror=', code: 'SEM_E018', message: 'onerror handler detected (XSS risk)' }\n    ];\n\n    for (const { tag, code, message } of dangerousTags) {\n      const lowerContent = content.toLowerCase();\n      if (lowerContent.includes(tag.toLowerCase())) {\n        const index = lowerContent.indexOf(tag.toLowerCase());\n        const lineInfo = this.getLineFromIndex(content, index);\n\n        this.addError(code, message, {\n          path,\n          severity: 'critical',\n          line: lineInfo.line,\n          column: lineInfo.column,\n          position: lineInfo.position,\n          lineText: lineInfo.lineText,\n          context: this.getContext(content, index, 50)\n        });\n      }","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/davila7/claude-code-templates/blob/a0851ed10c7c60463dac8cfaaca124cf32d5804d/cli-tool/src/validation/validators/SemanticValidator.js#L272-L308","documentation":"SEM_E018 is emitted by checkHtmlInjection when the content contains 'onerror=' (case-insensitive substring). onerror is a favorite XSS vector (e.g. <img src=x onerror=alert(1)>), so any occurrence in component markdown is reported.","triggerScenarios":"validate() where content.toLowerCase().includes('onerror='). Substring-based, so it fires on XSS payload examples in docs, React onError={...} props (after lowercasing), and copy-pasted HTML snippets alike.","commonSituations":"Security-explainer components that show the classic <img src=x onerror=...> payload; image-handling examples using an onError callback; HTML reference tables listing event attributes.","solutions":["Remove literal 'onerror=' from examples; describe the payload in prose or escape it ('on&#101;rror=')","For React onError props, restructure the example (destructure props or rename) so the exact substring 'onerror=' doesn't appear — remember matching is case-insensitive","For image error handling, show addEventListener('error', ...) in a script file"],"exampleFix":"# before\n<img src=x onerror=alert(1)>\n# after\nThe classic payload embeds an onerror handler in an img tag (escaped here).","handlingStrategy":"validation","validationCode":"if (component.content.toLowerCase().includes('onerror=')) {\n  // escape or describe the payload instead\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Don't paste onerror payloads verbatim in security docs","Use addEventListener('error', ...) in examples","Escape HTML attribute examples"],"tags":["xss","onerror-handler","static-analysis"],"backgroundTag":"xss-script-tag-detected","analyzedSha":"a0851ed10c7c60463dac8cfaaca124cf32d5804d","analyzedAt":"2026-08-28T14:11:56.058Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}