Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@contrast/reporter

Package Overview
Dependencies
Maintainers
17
Versions
62
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@contrast/reporter - npm Package Compare versions

Comparing version 1.1.0 to 1.2.0

166

lib/reporters/contrast-ui/app-activity-builder.js

@@ -19,3 +19,7 @@ "use strict";

const types_1 = require("./types");
const serverFeaturesRules = ['virtual-patch', 'ip-denylist'];
const mapInputType = (result) => {
/* c8 ignore next 31 */
if (result.inputType in types_1.InputType)
return result.inputType;
switch (result.inputType) {

@@ -48,8 +52,12 @@ case 'UriPath':

return types_1.InputType.XML_VALUE;
case 'Unknown':
return types_1.InputType.UNKNOWN;
}
};
const buildInputPayload = (result, time) => ({
name: result.key,
filters: result.mongoExpansionResult ? ['nosql-expansion'] : [],
name: result.key || '',
time,
type: mapInputType(result),
type: mapInputType(result) || 'UNKNOWN',
// NOTE: In v4 we have other documentTypes too, why pick only NORMAL?
documentType: types_1.DocumentType.NORMAL,

@@ -60,4 +68,15 @@ value: result.value,

const reflectedXSSDetailsBuilder = (el) => ({}); // TODO
const ssjsDetailsBuilder = (el) => ({}); // TODO
function default_1() {
const ssjsDetailsBuilder = (el) => {
if (!el.details || el.details.length === 0) {
return {};
}
const { findings } = el.details[0];
return {
start: findings.startIndex,
end: findings.endIndex,
boundaryOverrunIndex: findings.boundaryIndex,
codeString: findings.codeString,
};
};
const sqlInjectionDetailsBuilder = (el) => {

@@ -76,2 +95,15 @@ if (!el.details || el.details.length === 0) {

};
const nosqliMongoDetailsBuilder = (el) => {
if (!el.details || el.details.length === 0) {
return {};
}
const { findings: { start, end, boundaryOverrunIndex, inputBoundaryIndex }, sinkContext } = el.details[0];
return {
start,
end,
boundaryOverrunIndex,
inputBoundaryIndex,
query: typeof sinkContext.value === 'string' ? sinkContext.value : JSON.stringify(sinkContext.value),
};
};
const cmdInjectionDetailsBuilder = (el) => {

@@ -91,2 +123,17 @@ if (!el.details || el.details.length === 0) {

});
const cmdInjectionSemanticAnalysisDetailsBuilder = (el) => {
const ruleId = el.ruleId;
const ruleIdMap = {
[common_1.Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS]: 0,
[common_1.Rule.CMD_INJECTION_COMMAND_BACKDOORS]: 1,
[common_1.Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS]: 2
};
return {
command: el.value,
findings: [ruleIdMap[ruleId]]
};
};
const untrustedDeserializationDetailsBuilder = (el) => el.details?.[0];
const virtualPatchDetailsBuilder = (el) => el.details?.[0] || {};
const ipDenylistDetailsBuilder = (el) => el.details?.[0] || {};
const buildRequestObject = (reqData) => {

@@ -130,2 +177,5 @@ const searchParams = new URLSearchParams(reqData.queries);

: null;
if (result.ruleId === common_1.Rule.NOSQL_INJECTION_MONGO && typeof result.value !== 'string') {
result.mongoExpansionResult = true;
}
const data = {

@@ -145,3 +195,3 @@ details: detailsBuilder(result),

if (result.blocked) {
if (detail) {
if (detail && !serverFeaturesRules.includes(result.ruleId)) {
accumulator.blocked.total += 1;

@@ -223,2 +273,110 @@ accumulator.blocked.samples.push(data);

}
const nosqlInjectionMongo = protect.findings.resultsMap[common_1.Rule.NOSQL_INJECTION_MONGO];
if (nosqlInjectionMongo) {
const isBlockMode = protect.rules.agentLibRules[common_1.Rule.NOSQL_INJECTION_MONGO].mode === 'block';
const protectionRules = buildProtectionRules(nosqlInjectionMongo, requestPayload, time, isBlockMode, nosqliMongoDetailsBuilder);
if (protectionRules) {
defendObject.protectionRules[common_1.Rule.NOSQL_INJECTION] = protectionRules;
hasAttack = true;
}
}
const cmdiSemanticAnalysisDangerousPaths = protect.findings.semanticResultsMap[common_1.Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS];
if (cmdiSemanticAnalysisDangerousPaths) {
const isBlockMode = protect.rules.agentRules[common_1.Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS].mode === 'block';
cmdiSemanticAnalysisDangerousPaths.forEach((vulnerability) => {
Object.assign(vulnerability, {
inputType: 'Unknown',
key: 'Unknown',
value: vulnerability.findings?.command,
ruleId: common_1.Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS,
details: [{ ...vulnerability.findings }]
});
});
const protectionRules = buildProtectionRules(cmdiSemanticAnalysisDangerousPaths, requestPayload, time, isBlockMode, cmdInjectionSemanticAnalysisDetailsBuilder);
if (protectionRules) {
defendObject.protectionRules[common_1.Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS] = protectionRules;
hasAttack = true;
}
}
const cmdiSemanticAnalysisChainedCommands = protect.findings.semanticResultsMap[common_1.Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS];
if (cmdiSemanticAnalysisChainedCommands) {
const isBlockMode = protect.rules.agentRules[common_1.Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS].mode === 'block';
cmdiSemanticAnalysisChainedCommands.forEach((vulnerability) => {
Object.assign(vulnerability, {
inputType: 'Unknown',
key: 'Unknown',
value: vulnerability.findings?.command,
ruleId: common_1.Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS,
details: [{ ...vulnerability.findings }]
});
});
const protectionRules = buildProtectionRules(cmdiSemanticAnalysisChainedCommands, requestPayload, time, isBlockMode, cmdInjectionSemanticAnalysisDetailsBuilder);
if (protectionRules) {
defendObject.protectionRules[common_1.Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS] = protectionRules;
hasAttack = true;
}
}
const cmdiCommandBackdoors = protect.findings.semanticResultsMap[common_1.Rule.CMD_INJECTION_COMMAND_BACKDOORS];
if (cmdiCommandBackdoors) {
const isBlockMode = protect.rules.agentRules[common_1.Rule.CMD_INJECTION_COMMAND_BACKDOORS].mode === 'block';
cmdiCommandBackdoors.forEach((vulnerability) => {
Object.assign(vulnerability, {
ruleId: common_1.Rule.CMD_INJECTION_COMMAND_BACKDOORS,
details: [{ ...vulnerability.findings }],
});
});
const protectionRules = buildProtectionRules(cmdiCommandBackdoors, requestPayload, time, isBlockMode, cmdInjectionSemanticAnalysisDetailsBuilder);
if (protectionRules) {
defendObject.protectionRules[common_1.Rule.CMD_INJECTION_COMMAND_BACKDOORS] = protectionRules;
hasAttack = true;
}
}
const untrustedDeserialization = protect.findings.hardeningResultsMap[common_1.Rule.UNTRUSTED_DESERIALIZATION];
if (untrustedDeserialization) {
const isBlockMode = protect.rules.agentRules[common_1.Rule.UNTRUSTED_DESERIALIZATION].mode === 'block';
untrustedDeserialization.forEach((vulnerability) => {
Object.assign(vulnerability, {
ruleId: common_1.Rule.UNTRUSTED_DESERIALIZATION,
value: vulnerability.sinkContext.value,
details: [{ ...vulnerability.findings }],
});
});
const protectionRules = buildProtectionRules(untrustedDeserialization, requestPayload, time, isBlockMode, untrustedDeserializationDetailsBuilder);
if (protectionRules) {
defendObject.protectionRules[common_1.Rule.UNTRUSTED_DESERIALIZATION] = protectionRules;
hasAttack = true;
}
}
const virtualPatch = protect.findings.serverFeaturesResultsMap[common_1.Rule.VIRTUAL_PATCH];
if (virtualPatch) {
const mappedVirtualPatchResults = virtualPatch.map((vulnerability) => ({
key: vulnerability.name,
inputType: 'UNKNOWN',
ruleId: common_1.Rule.VIRTUAL_PATCH,
value: 'Virtual Patch',
details: [{ uuid: vulnerability.uuid }],
blocked: true
}));
const protectionRules = buildProtectionRules(mappedVirtualPatchResults, requestPayload, time, true, virtualPatchDetailsBuilder);
if (protectionRules) {
defendObject.protectionRules[common_1.Rule.VIRTUAL_PATCH] = protectionRules;
hasAttack = true;
}
}
const ipDenylist = protect.findings.serverFeaturesResultsMap[common_1.Rule.IP_DENYLIST];
if (ipDenylist) {
const mappedIpDenylist = ipDenylist.map((vulnerability) => ({
key: 'IP Address',
inputType: 'UNKNOWN',
ruleId: common_1.Rule.IP_DENYLIST,
value: vulnerability.ip,
details: [{ uuid: vulnerability.uuid, ip: vulnerability.ip }],
blocked: true
}));
const protectionRules = buildProtectionRules(mappedIpDenylist, requestPayload, time, true, ipDenylistDetailsBuilder);
if (protectionRules) {
defendObject.protectionRules['ip-blacklist'] = protectionRules;
hasAttack = true;
}
}
return hasAttack ? defendObject : null;

@@ -225,0 +383,0 @@ };

/// <reference types="node" />
import { RequestStore } from '@contrast/common';
import { RequestStore, Messages } from '@contrast/common';
import { AxiosInstance } from 'axios';

@@ -16,2 +16,3 @@ import { Core, AppInfo } from '@contrast/core';

lastUpdate: number;
lastServerUpdate: number;
activityLoop: NodeJS.Timeout | null;

@@ -21,2 +22,3 @@ httpClient: AxiosInstance;

scopes: Scopes;
messages: Messages;
userAgentSet: Set<string>;

@@ -29,2 +31,3 @@ defendPayload: AttackModel[];

private applicationActivity;
private serverActivity;
constructor(core: Core, name?: string, appActivityBuilder?: {

@@ -38,4 +41,5 @@ handleProtectMessage(protectMsg: import("@contrast/common").ProtectMessage): {

private initActivityLoop;
private serverSettingsUpdate;
handleAssessEvent(msg: RequestStore): void;
handleProtectEvent(msg: RequestStore): void;
}

@@ -29,2 +29,3 @@ "use strict";

this.lastUpdate = 0;
this.lastServerUpdate = 0;
this.activityLoop = null;

@@ -37,2 +38,3 @@ this.userAgentSet = new Set();

this.scopes = core.scopes;
this.messages = core.messages;
this.httpClient = axios_1.default.create({

@@ -122,9 +124,29 @@ baseURL: new URL(`${this.config.api.url}`).href,

}
serverActivity(serverActivityInMs) {
return this.httpClient
.put('/api/ng/activity/server', {
lastUpdate: this.lastServerUpdate + serverActivityInMs,
}, {
validateStatus(status) {
return status < 400;
},
})
.catch((error) => {
this.logger.error(error, 'Failed to update the server activity!');
throw error;
});
}
init() {
return this.startupServer() // settings from TS
.then((payload) => {
this.serverSettingsUpdate(payload);
})
.then(() => this.createApplication())
.then((payload) => {
this.serverSettingsUpdate(payload);
})
.then(() => this.initActivityLoop());
}
initActivityLoop() {
const appActivityInMs = this.config.agent.polling.app_activity_ms;
const activityIntervalInMs = this.config.agent.polling.app_activity_ms;
this.activityLoop = setInterval(() => {

@@ -135,5 +157,11 @@ const browsers = Array.from(this.userAgentSet.values());

this.defendPayload = [];
this.applicationActivity({ browsers }, { attackers }, appActivityInMs)
.then(() => {
this.lastUpdate += appActivityInMs;
this.applicationActivity({ browsers }, { attackers }, activityIntervalInMs)
.then((payload) => {
if (payload?.data) {
this.serverSettingsUpdate(payload);
this.lastUpdate = 0;
}
else {
this.lastUpdate += activityIntervalInMs;
}
})

@@ -147,4 +175,27 @@ .catch((error) => {

});
}, appActivityInMs).unref();
this.serverActivity(activityIntervalInMs)
.then((payload) => {
if (payload?.data) {
this.serverSettingsUpdate(payload);
this.lastServerUpdate = 0;
}
else {
this.lastServerUpdate += activityIntervalInMs;
}
})
.catch((error) => {
this.logger.error({
error,
}, 'Failed acquiring server activity!');
});
}, activityIntervalInMs).unref();
}
serverSettingsUpdate(serverPayload) {
// Ivaylo: IMO here we can plug in the code for dynamic rule mode update
// for now I'll not include it in this ticket(NODE-2503)
const serverUpdate = serverPayload?.data;
if (serverUpdate) {
this.messages.emit(common_1.Event.SERVER_SETTINGS_UPDATE, serverUpdate);
}
}
/* c8 ignore next 3 */

@@ -151,0 +202,0 @@ handleAssessEvent(msg) {

@@ -70,3 +70,10 @@ import { Rule } from '@contrast/common';

[Rule.SQL_INJECTION]?: SQLInjection;
[Rule.NOSQL_INJECTION]?: NoSQLInjection;
[Rule.SSJS_INJECTION]?: SSJSInjection;
[Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS]?: CMDInjectionSemanticAnalysis;
[Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS]?: CMDInjectionSemanticAnalysis;
[Rule.CMD_INJECTION_COMMAND_BACKDOORS]?: CMDInjectionSemanticAnalysis;
[Rule.UNTRUSTED_DESERIALIZATION]?: UntrustedDeserialization;
[Rule.VIRTUAL_PATCH]?: VirtualPatch;
'ip-blacklist'?: IpDenylist;
};

@@ -94,5 +101,40 @@ }

}
export interface CMDInjectionSemanticAnalysisDetails {
command: string;
findings: number[];
}
export interface UntrustedDeserializationDetails {
command: boolean;
deserializer: string;
}
export interface CMDInjectionSemanticAnalysis {
startTime: number;
exploited?: AttackBody<DefaultSample<CMDInjectionSemanticAnalysisDetails>>;
blocked?: AttackBody<DefaultSample<CMDInjectionSemanticAnalysisDetails>>;
blockedAtPerimeter?: AttackBody<DefaultSample<CMDInjectionSemanticAnalysisDetails>>;
}
export interface UntrustedDeserialization {
startTime: number;
exploited?: AttackBody<DefaultSample<UntrustedDeserializationDetails>>;
blocked?: AttackBody<DefaultSample<UntrustedDeserializationDetails>>;
blockedAtPerimeter?: AttackBody<DefaultSample<UntrustedDeserializationDetails>>;
}
export interface VirtualPatch {
startTime: number;
blockedAtPerimeter?: AttackBody<DefaultSample<VirtualPatchDetails>>;
}
export interface IpDenylist {
startTime: number;
blockedAtPerimeter?: AttackBody<DefaultSample<IpDenylistDetails>>;
}
export interface PathTraversalDetails {
path: string;
}
export interface VirtualPatchDetails {
uuid?: string;
}
export interface IpDenylistDetails {
uuid?: string;
ip?: string;
}
export interface PathTraversal {

@@ -123,2 +165,9 @@ startTime: number;

}
export interface NoSQLInjectionDetails {
start: number;
end: number;
boundaryOverrunIndex: number;
inputBoundaryIndex: number;
query: string;
}
export interface SQLInjection {

@@ -129,2 +178,7 @@ startTime: number;

}
export interface NoSQLInjection {
startTime: number;
exploited?: AttackBody<DefaultSample<NoSQLInjectionDetails>>;
blocked?: AttackBody<DefaultSample<NoSQLInjectionDetails>>;
}
export interface SSJSInjection {

@@ -131,0 +185,0 @@ startTime: number;

4

package.json
{
"name": "@contrast/reporter",
"version": "1.1.0",
"version": "1.2.0",
"description": "Subscribes to agent messages and reports them",

@@ -21,3 +21,3 @@ "license": "SEE LICENSE IN LICENSE",

"dependencies": {
"@contrast/common": "1.0.3",
"@contrast/common": "1.1.0",
"axios": "^0.27.2",

@@ -24,0 +24,0 @@ "safe-stable-stringify": "^2.3.1",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc