@hclsoftware/secagent
Version:
IAST agent
116 lines (101 loc) • 4.7 kB
JavaScript
//IASTIGNORE
/*
* ****************************************************
* Licensed Materials - Property of HCL.
* (c) Copyright HCL Technologies Ltd. 2017, 2025.
* Note to U.S. Government Users *Restricted Rights.
* ****************************************************
*/
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