Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ const { COMMAND_INJECTION } = require('../vulnerabilities')
class CommandInjectionAnalyzer extends InjectionAnalyzer {
constructor () {
super(COMMAND_INJECTION)
}

onConfigure () {
this.addSub('datadog:child_process:execution:start', ({ command }) => this.analyze(command))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ class CookieAnalyzer extends Analyzer {
constructor (type, propertyToBeSafe) {
super(type)
this.propertyToBeSafe = propertyToBeSafe.toLowerCase()
this.addSub('datadog:iast:set-cookie', (cookieInfo) => this.analyze(cookieInfo))
}

onConfigure () {
this.addSub(
{ channelName: 'datadog:iast:set-cookie', moduleName: 'http' },
(cookieInfo) => this.analyze(cookieInfo)
)
}

_isVulnerable ({ cookieProperties, cookieValue }) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ const { LDAP_INJECTION } = require('../vulnerabilities')
class LdapInjectionAnalyzer extends InjectionAnalyzer {
constructor () {
super(LDAP_INJECTION)
}

onConfigure () {
this.addSub('datadog:ldapjs:client:search', ({ base, filter }) => this.analyzeAll(base, filter))
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
'use strict'

const path = require('path')

const InjectionAnalyzer = require('./injection-analyzer')
const { getIastContext } = require('../iast-context')
const { storage } = require('../../../../../datadog-core')
const InjectionAnalyzer = require('./injection-analyzer')
const { PATH_TRAVERSAL } = require('../vulnerabilities')

const ignoredOperations = ['dir.close', 'close']

class PathTraversalAnalyzer extends InjectionAnalyzer {
constructor () {
super(PATH_TRAVERSAL)
this.addSub('apm:fs:operation:start', obj => {

this.exclusionList = [
path.join('node_modules', 'send') + path.sep
]

this.internalExclusionList = [
'node:fs',
'node:internal/fs',
'node:internal\\fs',
'fs.js',
'internal/fs',
'internal\\fs'
]
}

onConfigure () {
this.addSub('apm:fs:operation:start', (obj) => {
if (ignoredOperations.includes(obj.operation)) return

const pathArguments = []
Expand Down Expand Up @@ -44,19 +61,6 @@ class PathTraversalAnalyzer extends InjectionAnalyzer {
}
this.analyze(pathArguments)
})

this.exclusionList = [
path.join('node_modules', 'send') + path.sep
]

this.internalExclusionList = [
'node:fs',
'node:internal/fs',
'node:internal\\fs',
'fs.js',
'internal/fs',
'internal\\fs'
]
}

_isExcluded (location) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const EXCLUDED_PATHS = getNodeModulesPaths('mysql2', 'sequelize')
class SqlInjectionAnalyzer extends InjectionAnalyzer {
constructor () {
super(SQL_INJECTION)
}

onConfigure () {
this.addSub('apm:mysql:query:start', ({ sql }) => this.analyze(sql, 'MYSQL'))
this.addSub('apm:mysql2:query:start', ({ sql }) => this.analyze(sql, 'MYSQL'))
this.addSub('apm:pg:query:start', ({ query }) => this.analyze(query.text, 'POSTGRES'))
Expand Down Expand Up @@ -41,10 +44,9 @@ class SqlInjectionAnalyzer extends InjectionAnalyzer {

analyze (value, dialect) {
const store = storage.getStore()

if (!(store && store.sqlAnalyzed)) {
const iastContext = getIastContext(store)
if (store && !iastContext) return
if (this._isInvalidContext(store, iastContext)) return
this._reportIfVulnerable(value, iastContext, dialect)
}
}
Expand All @@ -66,6 +68,7 @@ class SqlInjectionAnalyzer extends InjectionAnalyzer {
addVulnerability(context, vulnerability)
}
}

_getExcludedPaths () {
return EXCLUDED_PATHS
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ const { SSRF } = require('../vulnerabilities')
class SSRFAnalyzer extends InjectionAnalyzer {
constructor () {
super(SSRF)
}

onConfigure () {
this.addSub('apm:http:client:request:start', ({ args }) => {
if (typeof args.originalUrl === 'string') {
this.analyze(args.originalUrl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ const InjectionAnalyzer = require('./injection-analyzer')
const { UNVALIDATED_REDIRECT } = require('../vulnerabilities')
const { getNodeModulesPaths } = require('../path-line')
const { getRanges } = require('../taint-tracking/operations')
const { HTTP_REQUEST_HEADER_VALUE } = require('../taint-tracking/origin-types')
const { HTTP_REQUEST_HEADER_VALUE } = require('../taint-tracking/source-types')

const EXCLUDED_PATHS = getNodeModulesPaths('express/lib/response.js')

class UnvalidatedRedirectAnalyzer extends InjectionAnalyzer {
constructor () {
super(UNVALIDATED_REDIRECT)
}

onConfigure () {
this.addSub('datadog:http:server:response:set-header:finish', ({ name, value }) => this.analyze(name, value))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,18 @@
'use strict'

const Plugin = require('../../../../src/plugins/plugin')
const { storage } = require('../../../../../datadog-core')
const iastLog = require('../iast-log')
const { getFirstNonDDPathAndLine } = require('../path-line')
const { addVulnerability } = require('../vulnerability-reporter')
const { getIastContext } = require('../iast-context')
const overheadController = require('../overhead-controller')
const { SinkIastPlugin } = require('../iast-plugin')

class Analyzer extends Plugin {
class Analyzer extends SinkIastPlugin {
constructor (type) {
super()
this._type = type
}

_wrapHandler (handler) {
return (message, name) => {
try {
handler(message, name)
} catch (e) {
iastLog.errorAndPublish(e)
}
}
}

addSub (channelName, handler) {
super.addSub(channelName, this._wrapHandler(handler))
}

_isVulnerable (value, context) {
return false
}
Expand Down Expand Up @@ -64,17 +49,23 @@ class Analyzer extends Plugin {

_getExcludedPaths () {}

_isInvalidContext (store, iastContext) {
return store && !iastContext
}

analyze (value) {
const store = storage.getStore()
const iastContext = getIastContext(store)
if (store && !iastContext) return
if (this._isInvalidContext(store, iastContext)) return

this._reportIfVulnerable(value, iastContext)
}

analyzeAll (...values) {
const store = storage.getStore()
const iastContext = getIastContext(store)
if (store && !iastContext) return
if (this._isInvalidContext(store, iastContext)) return

for (let i = 0; i < values.length; i++) {
const value = values[i]
if (this._isVulnerable(value, iastContext)) {
Expand Down Expand Up @@ -119,6 +110,14 @@ class Analyzer extends Plugin {
}
return hash
}

addSub (iastSubOrChannelName, handler) {
const iastSub = typeof iastSubOrChannelName === 'string'
? { channelName: iastSubOrChannelName }
: iastSubOrChannelName

super.addSub({ tag: this._type, ...iastSub }, handler)
}
}

module.exports = Analyzer
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const INSECURE_CIPHERS = new Set([
class WeakCipherAnalyzer extends Analyzer {
constructor () {
super(WEAK_CIPHER)
}

onConfigure () {
this.addSub('datadog:crypto:cipher:start', ({ algorithm }) => this.analyze(algorithm))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const EXCLUDED_PATHS_FROM_STACK = [
class WeakHashAnalyzer extends Analyzer {
constructor () {
super(WEAK_HASH)
}

onConfigure () {
this.addSub('datadog:crypto:hashing:start', ({ algorithm }) => this.analyze(algorithm))
}

Expand Down
2 changes: 1 addition & 1 deletion packages/dd-trace/src/appsec/iast/iast-log.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict'

const log = require('../../log')
const telemetryLogs = require('./telemetry/logs')
const telemetryLogs = require('./telemetry/log')
const { calculateDDBasePath } = require('../../util')

const ddBasePath = calculateDDBasePath(__dirname)
Expand Down
Loading