Skip to content

Commit 998afd1

Browse files
committed
feat: zipbomb detection using static analysis
1 parent 136755f commit 998afd1

File tree

4 files changed

+45
-8
lines changed

4 files changed

+45
-8
lines changed

package-lock.json

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"standard": "^11.0.1"
1919
},
2020
"dependencies": {
21+
"@ronomon/pure": "^1.0.4",
2122
"amazon-s3-uri": "0.0.3",
2223
"aws-sdk": "^2.300.0",
2324
"axios": "^0.18.0",

src/common/helper.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const m2mAuth = require('tc-core-library-js').auth.m2m
1313
const m2m = m2mAuth(_.pick(config, ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME', 'AUTH0_PROXY_SERVER_URL']))
1414
const AWS = require('aws-sdk')
1515
const AmazonS3URI = require('amazon-s3-uri')
16+
const pure = require("@ronomon/pure");
1617

1718
AWS.config.region = config.get('aws.REGION')
1819
const s3 = new AWS.S3()
@@ -39,11 +40,26 @@ function * downloadFile (fileURL) {
3940
}
4041
}
4142

42-
function * scanWithClamAV (fileURL) {
43-
// Download file from URL
44-
const downloadedFile = yield downloadFile(fileURL)
43+
/**
44+
* check if the file is a zipbomb
45+
*
46+
* @param {string} fileBuffer the file buffer
47+
* @returns
48+
*/
49+
function isZipBomb(fileBuffer) {
50+
const error = pure.zip(fileBuffer, 0);
51+
52+
// we only care about zip bombs
53+
if (error.code === "PURE_E_OK" || error.code.indexOf("ZIP_BOMB") === -1) {
54+
return [false];
55+
} else {
56+
return [true, error.code, error.message];
57+
}
58+
}
59+
60+
function * scanWithClamAV (file) {
4561
// Scan
46-
const fileStream = streamifier.createReadStream(downloadedFile)
62+
const fileStream = streamifier.createReadStream(file)
4763
return new Promise((resolve, reject) => {
4864
clamavScanner.scan(fileStream, (scanErr, object, malicious) => {
4965
if (scanErr) {
@@ -85,6 +101,7 @@ function * postToBusAPI (reqBody) {
85101
}
86102

87103
module.exports = {
104+
isZipBomb,
88105
scanWithClamAV,
89106
postToBusAPI
90107
}

src/services/ProcessorService.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,23 @@ const helper = require('../common/helper')
1111
* @param {Object} message the message
1212
*/
1313
function * processScan (message) {
14-
// Scan the file using ClamAV
15-
const isInfected = yield helper.scanWithClamAV(message.payload.url)
16-
// Update Scanning results
1714
message.timestamp = (new Date()).toISOString()
1815
message.payload.status = 'scanned'
16+
17+
const downloadedFile = yield helper.downloadFile(message.payload.url);
18+
19+
// Scan the file using ClamAV
20+
const [isZipBomb, errorCode, errorMessage] = helper.isZipBomb(downloadedFile);
21+
if (isZipBomb) {
22+
message.isInfected = true;
23+
logger.warn(`File at ${message.payload.url} is a ZipBomb. ${errorCode}: ${errorMessage}`);
24+
yield helper.postToBusAPI(message)
25+
return message;
26+
}
27+
28+
const isInfected = yield helper.scanWithClamAV(downloadedFile)
29+
30+
// Update Scanning results
1931
message.payload.isInfected = isInfected
2032

2133
yield helper.postToBusAPI(message)

0 commit comments

Comments
 (0)