mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-05-18 13:21:15 +08:00
fix: tighten supply-chain IOC package matching
This commit is contained in:
parent
eb59afb590
commit
7420441512
@ -493,6 +493,65 @@ function escapeRegExp(value) {
|
|||||||
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function versionSpecifierMatches(value, version) {
|
||||||
|
if (value === undefined || value === null) return false;
|
||||||
|
const specifier = String(value);
|
||||||
|
const versionPattern = new RegExp(`(^|[^0-9A-Za-z.])${escapeRegExp(version)}([^0-9A-Za-z.]|$)`, 'i');
|
||||||
|
return specifier === version || versionPattern.test(specifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
function packageKeyMatches(key, packageName) {
|
||||||
|
return key === packageName
|
||||||
|
|| key === `node_modules/${packageName}`
|
||||||
|
|| key.endsWith(`/node_modules/${packageName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jsonReferencesPackageVersion(value, packageName, version) {
|
||||||
|
if (!value || typeof value !== 'object') return false;
|
||||||
|
|
||||||
|
if (value.name === packageName && versionSpecifierMatches(value.version, version)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [key, child] of Object.entries(value)) {
|
||||||
|
if (packageKeyMatches(key, packageName)) {
|
||||||
|
if (typeof child === 'string' && versionSpecifierMatches(child, version)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (child && typeof child === 'object' && versionSpecifierMatches(child.version, version)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child && typeof child === 'object' && jsonReferencesPackageVersion(child, packageName, version)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function textReferencesPackageVersion(text, packageName, version) {
|
||||||
|
const escapedPackage = escapeRegExp(packageName);
|
||||||
|
const escapedVersion = escapeRegExp(version);
|
||||||
|
const packageToken = `${escapedPackage}(?![A-Za-z0-9._/-])`;
|
||||||
|
const sameLinePattern = new RegExp(`${packageToken}[^\\n]{0,200}${escapedVersion}(?![0-9A-Za-z.])`, 'i');
|
||||||
|
const requirementsPattern = new RegExp(`^\\s*${packageToken}\\s*(?:==|===|~=|>=|<=|>|<)\\s*${escapedVersion}(?![0-9A-Za-z.])`, 'im');
|
||||||
|
const poetryNamePattern = new RegExp(`name\\s*=\\s*["']${escapedPackage}["'][\\s\\S]{0,300}?version\\s*=\\s*["']${escapedVersion}["']`, 'i');
|
||||||
|
|
||||||
|
return sameLinePattern.test(text)
|
||||||
|
|| requirementsPattern.test(text)
|
||||||
|
|| poetryNamePattern.test(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
function dependencyFileReferencesPackageVersion(text, packageName, version) {
|
||||||
|
try {
|
||||||
|
return jsonReferencesPackageVersion(JSON.parse(text), packageName, version);
|
||||||
|
} catch {
|
||||||
|
return textReferencesPackageVersion(text, packageName, version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function addFinding(findings, severity, filePath, line, indicator, message) {
|
function addFinding(findings, severity, filePath, line, indicator, message) {
|
||||||
findings.push({ severity, filePath, line, indicator, message });
|
findings.push({ severity, filePath, line, indicator, message });
|
||||||
}
|
}
|
||||||
@ -543,17 +602,14 @@ function scanFile(filePath, rootDir, findings) {
|
|||||||
if (!DEPENDENCY_FILENAMES.has(base)) return;
|
if (!DEPENDENCY_FILENAMES.has(base)) return;
|
||||||
|
|
||||||
for (const [packageName, versions] of Object.entries(MALICIOUS_PACKAGE_VERSIONS)) {
|
for (const [packageName, versions] of Object.entries(MALICIOUS_PACKAGE_VERSIONS)) {
|
||||||
const packageIndex = lowerText.indexOf(normalizeForMatch(packageName));
|
|
||||||
if (packageIndex === -1) continue;
|
|
||||||
|
|
||||||
for (const version of versions) {
|
for (const version of versions) {
|
||||||
const versionPattern = new RegExp(`(^|[^0-9a-z.])${escapeRegExp(version)}([^0-9a-z.]|$)`, 'i');
|
if (dependencyFileReferencesPackageVersion(text, packageName, version)) {
|
||||||
if (versionPattern.test(text) || lowerText.includes(`@${version}`)) {
|
const packageIndex = lowerText.indexOf(normalizeForMatch(packageName));
|
||||||
addFinding(
|
addFinding(
|
||||||
findings,
|
findings,
|
||||||
'critical',
|
'critical',
|
||||||
relativePath,
|
relativePath,
|
||||||
lineForIndex(text, packageIndex),
|
lineForIndex(text, packageIndex === -1 ? 0 : packageIndex),
|
||||||
`${packageName}@${version}`,
|
`${packageName}@${version}`,
|
||||||
'Dependency manifest or lockfile references a known compromised package version',
|
'Dependency manifest or lockfile references a known compromised package version',
|
||||||
);
|
);
|
||||||
|
|||||||
@ -154,6 +154,30 @@ function run() {
|
|||||||
});
|
});
|
||||||
})) passed++; else failed++;
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
if (test('does not combine package-name substrings with unrelated versions', () => {
|
||||||
|
withFixture({
|
||||||
|
'package-lock.json': JSON.stringify({
|
||||||
|
packages: {
|
||||||
|
'node_modules/react-remove-scroll': {
|
||||||
|
version: '2.6.3',
|
||||||
|
},
|
||||||
|
'node_modules/@tailwindcss/node': {
|
||||||
|
version: '4.2.1',
|
||||||
|
dependencies: {
|
||||||
|
lightningcss: '1.31.1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'node_modules/lightningcss': {
|
||||||
|
version: '1.31.1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, null, 2),
|
||||||
|
}, rootDir => {
|
||||||
|
const result = scanSupplyChainIocs({ rootDir });
|
||||||
|
assert.deepStrictEqual(result.findings, []);
|
||||||
|
});
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
if (test('does not flag benign substrings in clean package scripts', () => {
|
if (test('does not flag benign substrings in clean package scripts', () => {
|
||||||
withFixture({
|
withFixture({
|
||||||
'node_modules/uuid/package.json': JSON.stringify({
|
'node_modules/uuid/package.json': JSON.stringify({
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user