@automagik/genie 4.260424.6 → 4.260424.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genie",
|
|
3
|
-
"version": "4.260424.
|
|
3
|
+
"version": "4.260424.8",
|
|
4
4
|
"description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, turn them into wishes, execute with /work, validate with /review, and ship as one team.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Namastex Labs"
|
package/scripts/sec-scan.cjs
CHANGED
|
@@ -1496,6 +1496,28 @@ function searchBufferForIocs(buffer) {
|
|
|
1496
1496
|
return uniq(hits);
|
|
1497
1497
|
}
|
|
1498
1498
|
|
|
1499
|
+
// An install finding is "hard evidence" only when the version matches the
|
|
1500
|
+
// compromised list OR a file hash matches a known malware hash. IOC-string
|
|
1501
|
+
// matches in file content are NOT hard evidence on their own — the scanner's
|
|
1502
|
+
// own source literally contains every IOC string as a detection pattern, so
|
|
1503
|
+
// scanning `@automagik/genie@<clean-version>` would always match itself
|
|
1504
|
+
// (the self-detection false positive fixed here).
|
|
1505
|
+
function hasHardInfectionEvidence(inspection) {
|
|
1506
|
+
if (inspection.compromisedVersion) return true;
|
|
1507
|
+
if (inspection.iocFileHashes.some((entry) => entry.knownMalwareHash === true)) return true;
|
|
1508
|
+
return false;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
// `@automagik/genie` is the scanner package itself. On CLEAN versions its
|
|
1512
|
+
// source files contain IOC strings as detection patterns — scanning its own
|
|
1513
|
+
// bytes therefore produces thousands of spurious `iocStrings` hits. Skip the
|
|
1514
|
+
// content walk entirely for clean versions of the scanner package.
|
|
1515
|
+
function shouldSkipContentWalk(packageName, version) {
|
|
1516
|
+
if (packageName !== '@automagik/genie') return false;
|
|
1517
|
+
if (!version) return false;
|
|
1518
|
+
return !isTrackedCompromisedVersion(packageName, version);
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1499
1521
|
function inspectPackageDirectory(packageDir) {
|
|
1500
1522
|
const result = {
|
|
1501
1523
|
path: packageDir,
|
|
@@ -1506,6 +1528,7 @@ function inspectPackageDirectory(packageDir) {
|
|
|
1506
1528
|
iocFiles: [],
|
|
1507
1529
|
iocFileHashes: [],
|
|
1508
1530
|
iocStrings: [],
|
|
1531
|
+
contentWalkSkipped: false,
|
|
1509
1532
|
};
|
|
1510
1533
|
|
|
1511
1534
|
const packageJsonPath = join(packageDir, 'package.json');
|
|
@@ -1540,6 +1563,11 @@ function inspectPackageDirectory(packageDir) {
|
|
|
1540
1563
|
});
|
|
1541
1564
|
}
|
|
1542
1565
|
|
|
1566
|
+
if (shouldSkipContentWalk(result.packageName, result.version)) {
|
|
1567
|
+
result.contentWalkSkipped = true;
|
|
1568
|
+
return result;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1543
1571
|
const stack = [packageDir];
|
|
1544
1572
|
while (stack.length > 0) {
|
|
1545
1573
|
const current = stack.pop();
|
|
@@ -1968,7 +1996,7 @@ function scanBunCache(homePath, report) {
|
|
|
1968
1996
|
if (!safeExists(bunGlobal)) continue;
|
|
1969
1997
|
|
|
1970
1998
|
const inspection = inspectPackageDirectory(bunGlobal);
|
|
1971
|
-
if (inspection
|
|
1999
|
+
if (hasHardInfectionEvidence(inspection)) {
|
|
1972
2000
|
const finding = {
|
|
1973
2001
|
kind: 'bun-global',
|
|
1974
2002
|
home: homePath,
|
|
@@ -2017,9 +2045,7 @@ function scanGlobalInstallCandidates(homes, report) {
|
|
|
2017
2045
|
|
|
2018
2046
|
for (const candidate of findTrackedPackageDirs(nodeModulesPath)) {
|
|
2019
2047
|
const inspection = inspectPackageDirectory(candidate);
|
|
2020
|
-
if (!inspection
|
|
2021
|
-
continue;
|
|
2022
|
-
}
|
|
2048
|
+
if (!hasHardInfectionEvidence(inspection)) continue;
|
|
2023
2049
|
|
|
2024
2050
|
const finding = {
|
|
2025
2051
|
kind: 'global-install',
|
|
@@ -2178,9 +2204,7 @@ function scanProjectRoots(roots, report, runtime) {
|
|
|
2178
2204
|
(nodeModulesPath) => {
|
|
2179
2205
|
for (const packageDir of findTrackedPackageDirs(nodeModulesPath)) {
|
|
2180
2206
|
const inspection = inspectPackageDirectory(packageDir);
|
|
2181
|
-
if (!inspection
|
|
2182
|
-
continue;
|
|
2183
|
-
}
|
|
2207
|
+
if (!hasHardInfectionEvidence(inspection)) continue;
|
|
2184
2208
|
|
|
2185
2209
|
const finding = {
|
|
2186
2210
|
kind: 'local-install',
|
|
@@ -2825,19 +2849,27 @@ function scanLiveProcesses(report) {
|
|
|
2825
2849
|
if (!match) continue;
|
|
2826
2850
|
|
|
2827
2851
|
const [, pid, ppid, user, elapsed, command] = match;
|
|
2852
|
+
|
|
2853
|
+
// Self-exclusion: the running scanner process itself always matches
|
|
2854
|
+
// `exec:@automagik/genie` in its own cmdline. Ignore it.
|
|
2855
|
+
if (command.includes('sec-scan.cjs') || command.includes('/sec-scan ')) continue;
|
|
2856
|
+
|
|
2828
2857
|
const indicators = collectTextIndicators(command);
|
|
2829
2858
|
const namedHits = collectNamedArtifactHits(command);
|
|
2830
2859
|
const matchedInstallPaths = suspectPaths.filter((path) => command.includes(path));
|
|
2831
2860
|
|
|
2832
|
-
|
|
2861
|
+
// Hard evidence requires either an actual compromised version token in
|
|
2862
|
+
// the cmdline OR an IOC string hit OR a network-IOC command. Pure name
|
|
2863
|
+
// matches (e.g. `pgserve@1.1.10` where 1.1.10 is CLEAN) are NOT compromise
|
|
2864
|
+
// evidence — they only tell us the package is running, which is normal.
|
|
2865
|
+
const hasHardEvidence =
|
|
2833
2866
|
indicators.iocMatches.length > 0 ||
|
|
2834
|
-
indicators.executionCommands.length > 0 ||
|
|
2835
2867
|
indicators.networkCommands.length > 0 ||
|
|
2836
2868
|
indicators.versions.length > 0 ||
|
|
2837
|
-
namedHits.length > 0 ||
|
|
2838
2869
|
matchedInstallPaths.length > 0;
|
|
2839
2870
|
|
|
2840
|
-
|
|
2871
|
+
const hasWeakHit = hasHardEvidence || indicators.executionCommands.length > 0 || namedHits.length > 0;
|
|
2872
|
+
if (!hasWeakHit) continue;
|
|
2841
2873
|
|
|
2842
2874
|
report.liveProcessFindings.push({
|
|
2843
2875
|
pid: Number(pid),
|
|
@@ -2851,13 +2883,16 @@ function scanLiveProcesses(report) {
|
|
|
2851
2883
|
executionCommands: indicators.executionCommands,
|
|
2852
2884
|
networkCommands: indicators.networkCommands,
|
|
2853
2885
|
nameMatches: namedHits,
|
|
2886
|
+
hardEvidence: hasHardEvidence,
|
|
2854
2887
|
});
|
|
2855
2888
|
|
|
2856
2889
|
addTimeline(report, {
|
|
2857
2890
|
time: null,
|
|
2858
2891
|
category: 'live-process',
|
|
2859
|
-
severity: 'compromised',
|
|
2860
|
-
summary:
|
|
2892
|
+
severity: hasHardEvidence ? 'compromised' : 'observed',
|
|
2893
|
+
summary: hasHardEvidence
|
|
2894
|
+
? `live process ${pid} matches suspicious package execution indicators`
|
|
2895
|
+
: `live process ${pid} running tracked package name (clean or unversioned) — informational`,
|
|
2861
2896
|
path: command,
|
|
2862
2897
|
});
|
|
2863
2898
|
}
|
|
@@ -2943,7 +2978,8 @@ function summarize(report) {
|
|
|
2943
2978
|
if (strongTempEvidence > 0) {
|
|
2944
2979
|
compromiseReasons.push('temp or cache directories retain dropped env-compat artifacts or IOC strings');
|
|
2945
2980
|
}
|
|
2946
|
-
|
|
2981
|
+
const hardEvidenceProcesses = report.liveProcessFindings.filter((entry) => entry.hardEvidence);
|
|
2982
|
+
if (hardEvidenceProcesses.length > 0) {
|
|
2947
2983
|
compromiseReasons.push('live processes match suspicious package execution indicators');
|
|
2948
2984
|
}
|
|
2949
2985
|
if (report.pythonPthFindings.length > 0) {
|
|
@@ -2983,7 +3019,7 @@ function summarize(report) {
|
|
|
2983
3019
|
suspicionScore += Math.min(strongProfileEvidence * 20, 40);
|
|
2984
3020
|
suspicionScore += Math.min(executionHistoryEvidence * 20, 40);
|
|
2985
3021
|
suspicionScore += Math.min(strongTempEvidence * 20, 40);
|
|
2986
|
-
suspicionScore += Math.min(
|
|
3022
|
+
suspicionScore += Math.min(hardEvidenceProcesses.length * 25, 50);
|
|
2987
3023
|
suspicionScore += Math.min(report.pythonPthFindings.length * 25, 50);
|
|
2988
3024
|
suspicionScore += Math.min(report.installFindings.length * 12, 24);
|
|
2989
3025
|
suspicionScore += Math.min(report.npmTarballFetches.length * 8, 24);
|