@inner-security/scan 0.1.0 → 0.1.2
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/bundle/index.d.ts +3 -3
- package/bundle/index.js +182 -7
- package/bundle/inner-cli.js +184 -21
- package/bundle/scan-cli.js +3 -9
- package/package.json +1 -1
package/bundle/index.d.ts
CHANGED
|
@@ -3,10 +3,10 @@ import { ScanClientResult, ResolvedItem } from '@inner/verdict-client';
|
|
|
3
3
|
export { DEFAULT_API_URL, ResolvedItem, ScanClientResult } from '@inner/verdict-client';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Default registry proxy base
|
|
7
|
-
*
|
|
6
|
+
* Default registry proxy base — the deployed Inner registry proxy (Cloudflare
|
|
7
|
+
* Worker). Override with INNER_PROXY_URL or `inner init --proxy <url>`.
|
|
8
8
|
*/
|
|
9
|
-
declare const DEFAULT_PROXY_URL = "https://proxy.
|
|
9
|
+
declare const DEFAULT_PROXY_URL = "https://inner-proxy.issa-e8f.workers.dev";
|
|
10
10
|
interface ResolvedConfig {
|
|
11
11
|
/** Verdict API base URL (no trailing slash). */
|
|
12
12
|
apiUrl: string;
|
package/bundle/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ../verdict-client/dist/client.js
|
|
2
|
-
var DEFAULT_API_URL = "
|
|
2
|
+
var DEFAULT_API_URL = "https://inner-verdict-api.issa-e8f.workers.dev";
|
|
3
3
|
function isPending(item) {
|
|
4
4
|
return item.action === "PENDING";
|
|
5
5
|
}
|
|
@@ -204,7 +204,7 @@ var VerdictClient = class {
|
|
|
204
204
|
};
|
|
205
205
|
|
|
206
206
|
// src/config.ts
|
|
207
|
-
var DEFAULT_PROXY_URL = "https://proxy.
|
|
207
|
+
var DEFAULT_PROXY_URL = "https://inner-proxy.issa-e8f.workers.dev";
|
|
208
208
|
function stripTrailingSlash2(u) {
|
|
209
209
|
return u.replace(/\/+$/, "");
|
|
210
210
|
}
|
|
@@ -646,6 +646,181 @@ function formatTally(t) {
|
|
|
646
646
|
// src/init.ts
|
|
647
647
|
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
648
648
|
import { join as join3 } from "path";
|
|
649
|
+
|
|
650
|
+
// ../contracts/dist/enums.js
|
|
651
|
+
var STATUS_TO_ACTION = {
|
|
652
|
+
benign: "ALLOW",
|
|
653
|
+
suspicious: "REVIEW",
|
|
654
|
+
malicious: "BLOCK",
|
|
655
|
+
unknown: "PENDING"
|
|
656
|
+
};
|
|
657
|
+
|
|
658
|
+
// ../contracts/dist/proxy.js
|
|
659
|
+
var PROXY_PATHS = {
|
|
660
|
+
npm: "/npm",
|
|
661
|
+
pypiSimple: "/pypi/simple",
|
|
662
|
+
pypiFiles: "/pypi/files"
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
// ../contracts/dist/fixtures.js
|
|
666
|
+
var NOW = "2026-06-27T00:00:00Z";
|
|
667
|
+
var WEEK = "2026-07-04T00:00:00Z";
|
|
668
|
+
function v(p) {
|
|
669
|
+
const status = p.status;
|
|
670
|
+
return {
|
|
671
|
+
ecosystem: "npm",
|
|
672
|
+
action: STATUS_TO_ACTION[status],
|
|
673
|
+
confidence: status === "malicious" ? 0.97 : status === "suspicious" ? 0.6 : 0.95,
|
|
674
|
+
behaviors: [],
|
|
675
|
+
corroboration: "behavioral_only",
|
|
676
|
+
evidence_uri: `s3://inner-evidence/${p.name}@${p.version}.json`,
|
|
677
|
+
engine_version: "v0.1.0",
|
|
678
|
+
scanned_at: NOW,
|
|
679
|
+
expires_at: WEEK,
|
|
680
|
+
engine_signature: "ed25519:STUB",
|
|
681
|
+
version_id: `${p.name}@${p.version}`,
|
|
682
|
+
...p
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
var SAMPLE_VERDICTS = [
|
|
686
|
+
// --- 10 malicious ---
|
|
687
|
+
// event-stream-style: real-world supply-chain attack (flatmap-stream payload).
|
|
688
|
+
v({
|
|
689
|
+
name: "event-stream",
|
|
690
|
+
version: "3.3.6",
|
|
691
|
+
status: "malicious",
|
|
692
|
+
content_hash: "sha256:bad1",
|
|
693
|
+
corroboration: "corroborated",
|
|
694
|
+
behaviors: [
|
|
695
|
+
{ category: "credential_theft", severity: "critical", evidence_ref: "trace#1" },
|
|
696
|
+
{ category: "c2_communication", severity: "high", evidence_ref: "trace#2" }
|
|
697
|
+
],
|
|
698
|
+
capabilities: [
|
|
699
|
+
{ capability: "reads_credentials", source: "hook" },
|
|
700
|
+
{ capability: "network_exfil", source: "network" }
|
|
701
|
+
]
|
|
702
|
+
}),
|
|
703
|
+
// Typosquat of 'react'.
|
|
704
|
+
v({
|
|
705
|
+
name: "reaact",
|
|
706
|
+
version: "1.0.0",
|
|
707
|
+
status: "malicious",
|
|
708
|
+
content_hash: "sha256:bad2",
|
|
709
|
+
corroboration: "corroborated",
|
|
710
|
+
behaviors: [{ category: "malicious_download", severity: "high", evidence_ref: "trace#1" }],
|
|
711
|
+
capabilities: [{ capability: "self_propagation", source: "static" }]
|
|
712
|
+
}),
|
|
713
|
+
// Behavioral-only: spawns shell during install. Behavioral_only → REVIEW until eval-certified.
|
|
714
|
+
v({
|
|
715
|
+
name: "left-pad-2",
|
|
716
|
+
version: "0.0.1",
|
|
717
|
+
status: "malicious",
|
|
718
|
+
content_hash: "sha256:bad3",
|
|
719
|
+
corroboration: "behavioral_only",
|
|
720
|
+
behaviors: [{ category: "command_execution", severity: "high", evidence_ref: "trace#1" }],
|
|
721
|
+
capabilities: [{ capability: "spawns_process", source: "syscall" }]
|
|
722
|
+
}),
|
|
723
|
+
// Postinstall script reads ~/.aws/credentials and POSTs to an external host.
|
|
724
|
+
v({
|
|
725
|
+
name: "aws-helper-cli",
|
|
726
|
+
version: "0.4.2",
|
|
727
|
+
status: "malicious",
|
|
728
|
+
content_hash: "sha256:bad4",
|
|
729
|
+
corroboration: "corroborated",
|
|
730
|
+
behaviors: [
|
|
731
|
+
{ category: "credential_theft", severity: "critical", evidence_ref: "trace#1" },
|
|
732
|
+
{ category: "data_exfiltration", severity: "critical", evidence_ref: "trace#2" }
|
|
733
|
+
],
|
|
734
|
+
capabilities: [
|
|
735
|
+
{ capability: "reads_credentials", source: "syscall" },
|
|
736
|
+
{ capability: "network_exfil", source: "network" }
|
|
737
|
+
]
|
|
738
|
+
}),
|
|
739
|
+
// Obfuscated eval(atob(...)) payload — dynamic code execution detected statically.
|
|
740
|
+
v({
|
|
741
|
+
name: "kazka-utils",
|
|
742
|
+
version: "2.1.0",
|
|
743
|
+
status: "malicious",
|
|
744
|
+
content_hash: "sha256:bad5",
|
|
745
|
+
corroboration: "behavioral_only",
|
|
746
|
+
behaviors: [{ category: "dynamic_code_execution", severity: "high", evidence_ref: "trace#1" }],
|
|
747
|
+
capabilities: [{ capability: "obfuscated_payload", source: "static" }]
|
|
748
|
+
}),
|
|
749
|
+
// PyPI: setup.py performs persistence write to ~/.bashrc.
|
|
750
|
+
v({
|
|
751
|
+
ecosystem: "pypi",
|
|
752
|
+
name: "colorama-utils",
|
|
753
|
+
version: "0.4.5",
|
|
754
|
+
status: "malicious",
|
|
755
|
+
content_hash: "sha256:bad6",
|
|
756
|
+
corroboration: "behavioral_only",
|
|
757
|
+
behaviors: [{ category: "persistence", severity: "high", evidence_ref: "trace#1" }],
|
|
758
|
+
capabilities: [{ capability: "persistence", source: "syscall" }]
|
|
759
|
+
}),
|
|
760
|
+
// C2 beacon over WebSocket on a regular interval — slow-lane confirmed.
|
|
761
|
+
v({
|
|
762
|
+
name: "discord-bot-helper",
|
|
763
|
+
version: "0.0.7",
|
|
764
|
+
status: "malicious",
|
|
765
|
+
content_hash: "sha256:bad7",
|
|
766
|
+
corroboration: "corroborated",
|
|
767
|
+
behaviors: [{ category: "c2_communication", severity: "critical", evidence_ref: "trace#1" }],
|
|
768
|
+
capabilities: [{ capability: "c2_beacon", source: "network" }]
|
|
769
|
+
}),
|
|
770
|
+
// PyPI typosquat: 'requrest' -> 'requests'. Reads env vars and writes /tmp/.x.
|
|
771
|
+
v({
|
|
772
|
+
ecosystem: "pypi",
|
|
773
|
+
name: "requrest",
|
|
774
|
+
version: "2.31.0",
|
|
775
|
+
status: "malicious",
|
|
776
|
+
content_hash: "sha256:bad8",
|
|
777
|
+
corroboration: "corroborated",
|
|
778
|
+
behaviors: [
|
|
779
|
+
{ category: "data_collection", severity: "medium", evidence_ref: "trace#1" },
|
|
780
|
+
{ category: "file_manipulation", severity: "medium", evidence_ref: "trace#2" }
|
|
781
|
+
],
|
|
782
|
+
capabilities: [
|
|
783
|
+
{ capability: "env_recon", source: "hook" },
|
|
784
|
+
{ capability: "modifies_files", source: "syscall" }
|
|
785
|
+
]
|
|
786
|
+
}),
|
|
787
|
+
// Reverse shell binding /bin/sh to a remote port during import.
|
|
788
|
+
v({
|
|
789
|
+
name: "fastly-cdn-uploader",
|
|
790
|
+
version: "1.0.0",
|
|
791
|
+
status: "malicious",
|
|
792
|
+
content_hash: "sha256:bad9",
|
|
793
|
+
corroboration: "corroborated",
|
|
794
|
+
behaviors: [{ category: "reverse_shell", severity: "critical", evidence_ref: "trace#1" }],
|
|
795
|
+
capabilities: [
|
|
796
|
+
{ capability: "spawns_process", source: "syscall" },
|
|
797
|
+
{ capability: "network_exfil", source: "network" }
|
|
798
|
+
]
|
|
799
|
+
}),
|
|
800
|
+
// Web-injection payload: serves modified content on import; common in browser-side attacks.
|
|
801
|
+
v({
|
|
802
|
+
name: "analytics-tracker-pro",
|
|
803
|
+
version: "3.0.0",
|
|
804
|
+
status: "malicious",
|
|
805
|
+
content_hash: "sha256:bad10",
|
|
806
|
+
corroboration: "behavioral_only",
|
|
807
|
+
behaviors: [{ category: "web_injection", severity: "medium", evidence_ref: "trace#1" }]
|
|
808
|
+
}),
|
|
809
|
+
// --- 10 benign ---
|
|
810
|
+
v({ name: "react", version: "18.3.1", status: "benign", content_hash: "sha256:ok1" }),
|
|
811
|
+
v({ name: "lodash", version: "4.17.21", status: "benign", content_hash: "sha256:ok2" }),
|
|
812
|
+
v({ name: "axios", version: "1.7.2", status: "benign", content_hash: "sha256:ok3" }),
|
|
813
|
+
v({ name: "typescript", version: "5.5.4", status: "benign", content_hash: "sha256:ok4" }),
|
|
814
|
+
v({ name: "express", version: "4.19.2", status: "benign", content_hash: "sha256:ok5" }),
|
|
815
|
+
v({ name: "vite", version: "5.4.0", status: "benign", content_hash: "sha256:ok6" }),
|
|
816
|
+
// Heavy native build (node-gyp). Long install time is legitimate, not malicious.
|
|
817
|
+
v({ name: "node-sass", version: "9.0.0", status: "benign", content_hash: "sha256:ok7" }),
|
|
818
|
+
v({ ecosystem: "pypi", name: "requests", version: "2.31.0", status: "benign", content_hash: "sha256:ok8" }),
|
|
819
|
+
v({ ecosystem: "pypi", name: "numpy", version: "1.26.4", status: "benign", content_hash: "sha256:ok9" }),
|
|
820
|
+
v({ ecosystem: "pypi", name: "pandas", version: "2.2.2", status: "benign", content_hash: "sha256:ok10" })
|
|
821
|
+
];
|
|
822
|
+
|
|
823
|
+
// src/init.ts
|
|
649
824
|
var ALL_PACKAGE_MANAGERS = [
|
|
650
825
|
"npm",
|
|
651
826
|
"pnpm",
|
|
@@ -655,10 +830,10 @@ var ALL_PACKAGE_MANAGERS = [
|
|
|
655
830
|
"uv"
|
|
656
831
|
];
|
|
657
832
|
function npmRegistry(proxy) {
|
|
658
|
-
return `${proxy}
|
|
833
|
+
return `${proxy}${PROXY_PATHS.npm}/`;
|
|
659
834
|
}
|
|
660
835
|
function pypiSimpleIndex(proxy) {
|
|
661
|
-
return `${proxy}
|
|
836
|
+
return `${proxy}${PROXY_PATHS.pypiSimple}/`;
|
|
662
837
|
}
|
|
663
838
|
function upsertLine(body, key, line) {
|
|
664
839
|
const lines = body.length ? body.split(/\r?\n/) : [];
|
|
@@ -774,7 +949,7 @@ function init(opts = {}) {
|
|
|
774
949
|
const root = opts.root ?? process.cwd();
|
|
775
950
|
const fromOpt = opts.proxyUrl?.trim();
|
|
776
951
|
const fromEnv = process.env.INNER_PROXY_URL?.trim();
|
|
777
|
-
const DEFAULT_PROXY = "https://proxy.
|
|
952
|
+
const DEFAULT_PROXY = "https://inner-proxy.issa-e8f.workers.dev";
|
|
778
953
|
const proxyUrl = (fromOpt || fromEnv || DEFAULT_PROXY).replace(/\/+$/, "");
|
|
779
954
|
const proxyUrlIsDefault = !fromOpt && !fromEnv;
|
|
780
955
|
const managers = opts.managers ?? ALL_PACKAGE_MANAGERS;
|
|
@@ -818,8 +993,8 @@ function parseArgs(argv) {
|
|
|
818
993
|
return out;
|
|
819
994
|
}
|
|
820
995
|
function flagString(flags, key) {
|
|
821
|
-
const
|
|
822
|
-
return typeof
|
|
996
|
+
const v2 = flags[key];
|
|
997
|
+
return typeof v2 === "string" ? v2 : void 0;
|
|
823
998
|
}
|
|
824
999
|
function flagBool(flags, key) {
|
|
825
1000
|
return flags[key] === true || flags[key] === "true";
|
package/bundle/inner-cli.js
CHANGED
|
@@ -33,15 +33,15 @@ function parseArgs(argv) {
|
|
|
33
33
|
return out;
|
|
34
34
|
}
|
|
35
35
|
function flagString(flags, key) {
|
|
36
|
-
const
|
|
37
|
-
return typeof
|
|
36
|
+
const v2 = flags[key];
|
|
37
|
+
return typeof v2 === "string" ? v2 : void 0;
|
|
38
38
|
}
|
|
39
39
|
function flagBool(flags, key) {
|
|
40
40
|
return flags[key] === true || flags[key] === "true";
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
// ../verdict-client/dist/client.js
|
|
44
|
-
var DEFAULT_API_URL = "
|
|
44
|
+
var DEFAULT_API_URL = "https://inner-verdict-api.issa-e8f.workers.dev";
|
|
45
45
|
function isPending(item) {
|
|
46
46
|
return item.action === "PENDING";
|
|
47
47
|
}
|
|
@@ -246,7 +246,7 @@ var VerdictClient = class {
|
|
|
246
246
|
};
|
|
247
247
|
|
|
248
248
|
// src/config.ts
|
|
249
|
-
var DEFAULT_PROXY_URL = "https://proxy.
|
|
249
|
+
var DEFAULT_PROXY_URL = "https://inner-proxy.issa-e8f.workers.dev";
|
|
250
250
|
function stripTrailingSlash2(u) {
|
|
251
251
|
return u.replace(/\/+$/, "");
|
|
252
252
|
}
|
|
@@ -746,12 +746,6 @@ function writeText(result) {
|
|
|
746
746
|
if (result.degraded) {
|
|
747
747
|
process.stdout.write(
|
|
748
748
|
` (API unreachable \u2014 ${t.fromCache} resolved from fail-open cache, others marked unknown)
|
|
749
|
-
`
|
|
750
|
-
);
|
|
751
|
-
}
|
|
752
|
-
if (result.apiUrlIsDefault) {
|
|
753
|
-
process.stdout.write(
|
|
754
|
-
` note: using default Verdict API ${result.apiUrl} \u2014 set INNER_API_URL to the production endpoint.
|
|
755
749
|
`
|
|
756
750
|
);
|
|
757
751
|
}
|
|
@@ -770,6 +764,181 @@ function writeText(result) {
|
|
|
770
764
|
// src/init.ts
|
|
771
765
|
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
772
766
|
import { join as join3 } from "path";
|
|
767
|
+
|
|
768
|
+
// ../contracts/dist/enums.js
|
|
769
|
+
var STATUS_TO_ACTION = {
|
|
770
|
+
benign: "ALLOW",
|
|
771
|
+
suspicious: "REVIEW",
|
|
772
|
+
malicious: "BLOCK",
|
|
773
|
+
unknown: "PENDING"
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
// ../contracts/dist/proxy.js
|
|
777
|
+
var PROXY_PATHS = {
|
|
778
|
+
npm: "/npm",
|
|
779
|
+
pypiSimple: "/pypi/simple",
|
|
780
|
+
pypiFiles: "/pypi/files"
|
|
781
|
+
};
|
|
782
|
+
|
|
783
|
+
// ../contracts/dist/fixtures.js
|
|
784
|
+
var NOW = "2026-06-27T00:00:00Z";
|
|
785
|
+
var WEEK = "2026-07-04T00:00:00Z";
|
|
786
|
+
function v(p) {
|
|
787
|
+
const status = p.status;
|
|
788
|
+
return {
|
|
789
|
+
ecosystem: "npm",
|
|
790
|
+
action: STATUS_TO_ACTION[status],
|
|
791
|
+
confidence: status === "malicious" ? 0.97 : status === "suspicious" ? 0.6 : 0.95,
|
|
792
|
+
behaviors: [],
|
|
793
|
+
corroboration: "behavioral_only",
|
|
794
|
+
evidence_uri: `s3://inner-evidence/${p.name}@${p.version}.json`,
|
|
795
|
+
engine_version: "v0.1.0",
|
|
796
|
+
scanned_at: NOW,
|
|
797
|
+
expires_at: WEEK,
|
|
798
|
+
engine_signature: "ed25519:STUB",
|
|
799
|
+
version_id: `${p.name}@${p.version}`,
|
|
800
|
+
...p
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
var SAMPLE_VERDICTS = [
|
|
804
|
+
// --- 10 malicious ---
|
|
805
|
+
// event-stream-style: real-world supply-chain attack (flatmap-stream payload).
|
|
806
|
+
v({
|
|
807
|
+
name: "event-stream",
|
|
808
|
+
version: "3.3.6",
|
|
809
|
+
status: "malicious",
|
|
810
|
+
content_hash: "sha256:bad1",
|
|
811
|
+
corroboration: "corroborated",
|
|
812
|
+
behaviors: [
|
|
813
|
+
{ category: "credential_theft", severity: "critical", evidence_ref: "trace#1" },
|
|
814
|
+
{ category: "c2_communication", severity: "high", evidence_ref: "trace#2" }
|
|
815
|
+
],
|
|
816
|
+
capabilities: [
|
|
817
|
+
{ capability: "reads_credentials", source: "hook" },
|
|
818
|
+
{ capability: "network_exfil", source: "network" }
|
|
819
|
+
]
|
|
820
|
+
}),
|
|
821
|
+
// Typosquat of 'react'.
|
|
822
|
+
v({
|
|
823
|
+
name: "reaact",
|
|
824
|
+
version: "1.0.0",
|
|
825
|
+
status: "malicious",
|
|
826
|
+
content_hash: "sha256:bad2",
|
|
827
|
+
corroboration: "corroborated",
|
|
828
|
+
behaviors: [{ category: "malicious_download", severity: "high", evidence_ref: "trace#1" }],
|
|
829
|
+
capabilities: [{ capability: "self_propagation", source: "static" }]
|
|
830
|
+
}),
|
|
831
|
+
// Behavioral-only: spawns shell during install. Behavioral_only → REVIEW until eval-certified.
|
|
832
|
+
v({
|
|
833
|
+
name: "left-pad-2",
|
|
834
|
+
version: "0.0.1",
|
|
835
|
+
status: "malicious",
|
|
836
|
+
content_hash: "sha256:bad3",
|
|
837
|
+
corroboration: "behavioral_only",
|
|
838
|
+
behaviors: [{ category: "command_execution", severity: "high", evidence_ref: "trace#1" }],
|
|
839
|
+
capabilities: [{ capability: "spawns_process", source: "syscall" }]
|
|
840
|
+
}),
|
|
841
|
+
// Postinstall script reads ~/.aws/credentials and POSTs to an external host.
|
|
842
|
+
v({
|
|
843
|
+
name: "aws-helper-cli",
|
|
844
|
+
version: "0.4.2",
|
|
845
|
+
status: "malicious",
|
|
846
|
+
content_hash: "sha256:bad4",
|
|
847
|
+
corroboration: "corroborated",
|
|
848
|
+
behaviors: [
|
|
849
|
+
{ category: "credential_theft", severity: "critical", evidence_ref: "trace#1" },
|
|
850
|
+
{ category: "data_exfiltration", severity: "critical", evidence_ref: "trace#2" }
|
|
851
|
+
],
|
|
852
|
+
capabilities: [
|
|
853
|
+
{ capability: "reads_credentials", source: "syscall" },
|
|
854
|
+
{ capability: "network_exfil", source: "network" }
|
|
855
|
+
]
|
|
856
|
+
}),
|
|
857
|
+
// Obfuscated eval(atob(...)) payload — dynamic code execution detected statically.
|
|
858
|
+
v({
|
|
859
|
+
name: "kazka-utils",
|
|
860
|
+
version: "2.1.0",
|
|
861
|
+
status: "malicious",
|
|
862
|
+
content_hash: "sha256:bad5",
|
|
863
|
+
corroboration: "behavioral_only",
|
|
864
|
+
behaviors: [{ category: "dynamic_code_execution", severity: "high", evidence_ref: "trace#1" }],
|
|
865
|
+
capabilities: [{ capability: "obfuscated_payload", source: "static" }]
|
|
866
|
+
}),
|
|
867
|
+
// PyPI: setup.py performs persistence write to ~/.bashrc.
|
|
868
|
+
v({
|
|
869
|
+
ecosystem: "pypi",
|
|
870
|
+
name: "colorama-utils",
|
|
871
|
+
version: "0.4.5",
|
|
872
|
+
status: "malicious",
|
|
873
|
+
content_hash: "sha256:bad6",
|
|
874
|
+
corroboration: "behavioral_only",
|
|
875
|
+
behaviors: [{ category: "persistence", severity: "high", evidence_ref: "trace#1" }],
|
|
876
|
+
capabilities: [{ capability: "persistence", source: "syscall" }]
|
|
877
|
+
}),
|
|
878
|
+
// C2 beacon over WebSocket on a regular interval — slow-lane confirmed.
|
|
879
|
+
v({
|
|
880
|
+
name: "discord-bot-helper",
|
|
881
|
+
version: "0.0.7",
|
|
882
|
+
status: "malicious",
|
|
883
|
+
content_hash: "sha256:bad7",
|
|
884
|
+
corroboration: "corroborated",
|
|
885
|
+
behaviors: [{ category: "c2_communication", severity: "critical", evidence_ref: "trace#1" }],
|
|
886
|
+
capabilities: [{ capability: "c2_beacon", source: "network" }]
|
|
887
|
+
}),
|
|
888
|
+
// PyPI typosquat: 'requrest' -> 'requests'. Reads env vars and writes /tmp/.x.
|
|
889
|
+
v({
|
|
890
|
+
ecosystem: "pypi",
|
|
891
|
+
name: "requrest",
|
|
892
|
+
version: "2.31.0",
|
|
893
|
+
status: "malicious",
|
|
894
|
+
content_hash: "sha256:bad8",
|
|
895
|
+
corroboration: "corroborated",
|
|
896
|
+
behaviors: [
|
|
897
|
+
{ category: "data_collection", severity: "medium", evidence_ref: "trace#1" },
|
|
898
|
+
{ category: "file_manipulation", severity: "medium", evidence_ref: "trace#2" }
|
|
899
|
+
],
|
|
900
|
+
capabilities: [
|
|
901
|
+
{ capability: "env_recon", source: "hook" },
|
|
902
|
+
{ capability: "modifies_files", source: "syscall" }
|
|
903
|
+
]
|
|
904
|
+
}),
|
|
905
|
+
// Reverse shell binding /bin/sh to a remote port during import.
|
|
906
|
+
v({
|
|
907
|
+
name: "fastly-cdn-uploader",
|
|
908
|
+
version: "1.0.0",
|
|
909
|
+
status: "malicious",
|
|
910
|
+
content_hash: "sha256:bad9",
|
|
911
|
+
corroboration: "corroborated",
|
|
912
|
+
behaviors: [{ category: "reverse_shell", severity: "critical", evidence_ref: "trace#1" }],
|
|
913
|
+
capabilities: [
|
|
914
|
+
{ capability: "spawns_process", source: "syscall" },
|
|
915
|
+
{ capability: "network_exfil", source: "network" }
|
|
916
|
+
]
|
|
917
|
+
}),
|
|
918
|
+
// Web-injection payload: serves modified content on import; common in browser-side attacks.
|
|
919
|
+
v({
|
|
920
|
+
name: "analytics-tracker-pro",
|
|
921
|
+
version: "3.0.0",
|
|
922
|
+
status: "malicious",
|
|
923
|
+
content_hash: "sha256:bad10",
|
|
924
|
+
corroboration: "behavioral_only",
|
|
925
|
+
behaviors: [{ category: "web_injection", severity: "medium", evidence_ref: "trace#1" }]
|
|
926
|
+
}),
|
|
927
|
+
// --- 10 benign ---
|
|
928
|
+
v({ name: "react", version: "18.3.1", status: "benign", content_hash: "sha256:ok1" }),
|
|
929
|
+
v({ name: "lodash", version: "4.17.21", status: "benign", content_hash: "sha256:ok2" }),
|
|
930
|
+
v({ name: "axios", version: "1.7.2", status: "benign", content_hash: "sha256:ok3" }),
|
|
931
|
+
v({ name: "typescript", version: "5.5.4", status: "benign", content_hash: "sha256:ok4" }),
|
|
932
|
+
v({ name: "express", version: "4.19.2", status: "benign", content_hash: "sha256:ok5" }),
|
|
933
|
+
v({ name: "vite", version: "5.4.0", status: "benign", content_hash: "sha256:ok6" }),
|
|
934
|
+
// Heavy native build (node-gyp). Long install time is legitimate, not malicious.
|
|
935
|
+
v({ name: "node-sass", version: "9.0.0", status: "benign", content_hash: "sha256:ok7" }),
|
|
936
|
+
v({ ecosystem: "pypi", name: "requests", version: "2.31.0", status: "benign", content_hash: "sha256:ok8" }),
|
|
937
|
+
v({ ecosystem: "pypi", name: "numpy", version: "1.26.4", status: "benign", content_hash: "sha256:ok9" }),
|
|
938
|
+
v({ ecosystem: "pypi", name: "pandas", version: "2.2.2", status: "benign", content_hash: "sha256:ok10" })
|
|
939
|
+
];
|
|
940
|
+
|
|
941
|
+
// src/init.ts
|
|
773
942
|
var ALL_PACKAGE_MANAGERS = [
|
|
774
943
|
"npm",
|
|
775
944
|
"pnpm",
|
|
@@ -779,10 +948,10 @@ var ALL_PACKAGE_MANAGERS = [
|
|
|
779
948
|
"uv"
|
|
780
949
|
];
|
|
781
950
|
function npmRegistry(proxy) {
|
|
782
|
-
return `${proxy}
|
|
951
|
+
return `${proxy}${PROXY_PATHS.npm}/`;
|
|
783
952
|
}
|
|
784
953
|
function pypiSimpleIndex(proxy) {
|
|
785
|
-
return `${proxy}
|
|
954
|
+
return `${proxy}${PROXY_PATHS.pypiSimple}/`;
|
|
786
955
|
}
|
|
787
956
|
function upsertLine(body, key, line) {
|
|
788
957
|
const lines = body.length ? body.split(/\r?\n/) : [];
|
|
@@ -898,7 +1067,7 @@ function init(opts = {}) {
|
|
|
898
1067
|
const root = opts.root ?? process.cwd();
|
|
899
1068
|
const fromOpt = opts.proxyUrl?.trim();
|
|
900
1069
|
const fromEnv = process.env.INNER_PROXY_URL?.trim();
|
|
901
|
-
const DEFAULT_PROXY = "https://proxy.
|
|
1070
|
+
const DEFAULT_PROXY = "https://inner-proxy.issa-e8f.workers.dev";
|
|
902
1071
|
const proxyUrl = (fromOpt || fromEnv || DEFAULT_PROXY).replace(/\/+$/, "");
|
|
903
1072
|
const proxyUrlIsDefault = !fromOpt && !fromEnv;
|
|
904
1073
|
const managers = opts.managers ?? ALL_PACKAGE_MANAGERS;
|
|
@@ -918,12 +1087,12 @@ Usage:
|
|
|
918
1087
|
|
|
919
1088
|
init options:
|
|
920
1089
|
--dir <path> Project root to write config into (default: cwd)
|
|
921
|
-
--proxy <url> Registry proxy base URL (default: $INNER_PROXY_URL or
|
|
1090
|
+
--proxy <url> Registry proxy base URL (default: $INNER_PROXY_URL or the Inner proxy)
|
|
922
1091
|
--managers <list> Comma-separated subset of: ${ALL_PACKAGE_MANAGERS.join(",")}
|
|
923
1092
|
|
|
924
1093
|
scan options:
|
|
925
1094
|
--dir <path> Project root to scan (default: cwd)
|
|
926
|
-
--api-url <url> Verdict API base URL (default: $INNER_API_URL or
|
|
1095
|
+
--api-url <url> Verdict API base URL (default: $INNER_API_URL or the Inner Verdict API)
|
|
927
1096
|
--json Machine-readable JSON output
|
|
928
1097
|
--no-cache Skip the fail-open .inner-cache/
|
|
929
1098
|
|
|
@@ -952,12 +1121,6 @@ async function runInit(flags) {
|
|
|
952
1121
|
process.stdout.write(` registry: ${c.registry}
|
|
953
1122
|
`);
|
|
954
1123
|
}
|
|
955
|
-
if (result.proxyUrlIsDefault) {
|
|
956
|
-
process.stdout.write(
|
|
957
|
-
` note: using placeholder proxy ${result.proxyUrl} \u2014 set INNER_PROXY_URL or --proxy to the production proxy host.
|
|
958
|
-
`
|
|
959
|
-
);
|
|
960
|
-
}
|
|
961
1124
|
return 0;
|
|
962
1125
|
}
|
|
963
1126
|
async function runScan(flags) {
|
package/bundle/scan-cli.js
CHANGED
|
@@ -41,7 +41,7 @@ function flagBool(flags, key) {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
// ../verdict-client/dist/client.js
|
|
44
|
-
var DEFAULT_API_URL = "
|
|
44
|
+
var DEFAULT_API_URL = "https://inner-verdict-api.issa-e8f.workers.dev";
|
|
45
45
|
function isPending(item) {
|
|
46
46
|
return item.action === "PENDING";
|
|
47
47
|
}
|
|
@@ -246,7 +246,7 @@ var VerdictClient = class {
|
|
|
246
246
|
};
|
|
247
247
|
|
|
248
248
|
// src/config.ts
|
|
249
|
-
var DEFAULT_PROXY_URL = "https://proxy.
|
|
249
|
+
var DEFAULT_PROXY_URL = "https://inner-proxy.issa-e8f.workers.dev";
|
|
250
250
|
function stripTrailingSlash2(u) {
|
|
251
251
|
return u.replace(/\/+$/, "");
|
|
252
252
|
}
|
|
@@ -746,12 +746,6 @@ function writeText(result) {
|
|
|
746
746
|
if (result.degraded) {
|
|
747
747
|
process.stdout.write(
|
|
748
748
|
` (API unreachable \u2014 ${t.fromCache} resolved from fail-open cache, others marked unknown)
|
|
749
|
-
`
|
|
750
|
-
);
|
|
751
|
-
}
|
|
752
|
-
if (result.apiUrlIsDefault) {
|
|
753
|
-
process.stdout.write(
|
|
754
|
-
` note: using default Verdict API ${result.apiUrl} \u2014 set INNER_API_URL to the production endpoint.
|
|
755
749
|
`
|
|
756
750
|
);
|
|
757
751
|
}
|
|
@@ -775,7 +769,7 @@ Usage:
|
|
|
775
769
|
|
|
776
770
|
Options:
|
|
777
771
|
--dir <path> Project root to scan (default: cwd)
|
|
778
|
-
--api-url <url> Verdict API base URL (default: $INNER_API_URL or
|
|
772
|
+
--api-url <url> Verdict API base URL (default: $INNER_API_URL or the Inner Verdict API)
|
|
779
773
|
--json Emit machine-readable JSON instead of the text tally
|
|
780
774
|
--no-cache Do not read/write the fail-open .inner-cache/
|
|
781
775
|
-h, --help Show this help
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inner-security/scan",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Inner CLI: `@inner-security/scan` zero-auth instant dependency scan + `inner init` to route the 6 package managers through the Inner proxy. A thin client of Inner's Verdict API, gated by an org API key.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|