UNPKG

@hclsoftware/secagent

Version:

IAST agent

116 lines (101 loc) 4.7 kB
//IASTIGNORE /* * **************************************************** * Licensed Materials - Property of HCL. * (c) Copyright HCL Technologies Ltd. 2017, 2025. * Note to U.S. Government Users *Restricted Rights. * **************************************************** */ 'use strict' const SinkTask = require('./SinkTask') const TaskType = require('./TaskType') const VerificationTracker = require('../Verification/VerificationTracker') const TaintTracker = require('../TaintTracker') const Vulnerability = require('../Vulnerability') const IastLogger = require('../Logger/IastLogger') const {SinkInfoStringGenerator} = require("./SinkInfo/SinkInfoStringGenerator") const SinkTaskInfo = require("./SinkInfo/SinkTaskInfo") const logger = IastLogger.eventLog class XssSinkTask extends SinkTask.SinkTask { constructor (source, vulnerability, stack, parameters) { super(source, vulnerability, stack, parameters) if (this.vulnerability !== Vulnerability.XSS) { logger.error(`XssSinkTask with vulnerability: ${this.vulnerability}`) } this.taskType = TaskType.XSS_SINK } performAction () { // We have a list of validators and sanitizers that have been run on a string. In order to validate that they actually work, we need // to send through multiple tainted strings and see whether they were validated or not. let exploitExample = null let sinkTaskInfo let vulnerabilitySanitized = true const signature = this.getTasksInfo() const verified = VerificationTracker.getVerifiedState(signature, this.vulnerability) if (verified == null) { logger.debug(`Checking vulnerability ${Vulnerability} for signature ${signature}`) for (const currentExploit of exploits) { const origVal = this.taintedObjectFlow.entity.value const exploitWithOrigValues = [origVal, currentExploit, origVal].origJoin('') const result = this.traverseExploit(exploitWithOrigValues) if (result != null && this.resultIsTainted(result)) { vulnerabilitySanitized = false exploitExample = currentExploit break // validation failed here } } if (vulnerabilitySanitized) { logger.debug(`Signature ${signature} is verified as a sanitizer`) } else { logger.debug(`Signature ${signature} is verified as vulnerable`) } sinkTaskInfo = new SinkTaskInfo(exploitExample) VerificationTracker.setSignatureAsVerified(signature, this.vulnerability, vulnerabilitySanitized, sinkTaskInfo) } else { logger.debug(`Signature ${signature} was already verified`) sinkTaskInfo = verified.sinkInfo vulnerabilitySanitized = verified.verifiedOk // Whether the vulnerability is sanitized will be set by the validated flag, not this flag. } // If we could not run a valid test or the vulnerability was sanitized in all our tests, we will define this path as sanitized // This can be a configuration flag one day. if (vulnerabilitySanitized) { this.taintedObjectFlow.sanitize(this.vulnerability) } else { // We only call sink if the sanitization process is found to be not valid. TaintTracker.sinkTaskTrigger(this.taintedObjectFlow, this.vulnerability, new SinkInfoStringGenerator(sinkTaskInfo), true, this.stack, this.parameters) } return !vulnerabilitySanitized } resultIsTainted (result) { // If we can further escape the result, then we have not sanitized it. for (const char of illegalChars) { if (result.origStringIncludes(char)) return true } return false } } const exploits = [ ">'><script>alert(1)</script>", '>"><script>alert(1)</script>', ">'><%00script>alert(1)</script>", '>"><%00script>alert(1)</script>', '"></STYLE><STYLE>@import"javascript:alert(1)";</STYLE>', '"></IFRAME><script>alert(1)</script>', '"></style><script>alert(1)</script>', '"></title><script>alert(1)</script>', "'\"><iframe src=javascript:alert(1)>", '\\u003Cscript\\u003Ealert\\u00281\\u0029\\u003C/script\\u003E', '%27%22%3E%3Cscript%3Ealert%281%29%3C%2Fscript%3E', '%2522%253E%2527%253E%253Cscript%2520%253Ealert%25281%2529%253B%253C%252Fscript%2520%253E', "'\"</script><svg/onload=alert(1) width=100/>", "'\"</script><svg/onload=alert(1) width=100/>", '/</script/>/<svg/onload=alert(1) width=100//>', '/</script/>/<svg/onload=alert(1) width=100//>', '//</script//>//<svg/onload=alert(1) width=100///>', '//</script//>//<svg/onload=alert(1) width=100///>', '\\</script\\>\\<svg/onload=alert(1) width=100\\/>', '\\</script\\>\\<svg/onload=alert(1) width=100\\/>' ] const illegalChars = ['&', '<', '>', "'", '"'] module.exports = XssSinkTask