insa-check-core 0.1.0
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/LICENSE +24 -0
- package/dist/annex-b.d.ts +6 -0
- package/dist/annex-b.d.ts.map +1 -0
- package/dist/annex-b.js +152 -0
- package/dist/annex-b.js.map +1 -0
- package/dist/checks/content/page.d.ts +7 -0
- package/dist/checks/content/page.d.ts.map +1 -0
- package/dist/checks/content/page.js +133 -0
- package/dist/checks/content/page.js.map +1 -0
- package/dist/checks/cookies/cookie-flags.d.ts +3 -0
- package/dist/checks/cookies/cookie-flags.d.ts.map +1 -0
- package/dist/checks/cookies/cookie-flags.js +41 -0
- package/dist/checks/cookies/cookie-flags.js.map +1 -0
- package/dist/checks/cookies/cookie-scope.d.ts +6 -0
- package/dist/checks/cookies/cookie-scope.d.ts.map +1 -0
- package/dist/checks/cookies/cookie-scope.js +60 -0
- package/dist/checks/cookies/cookie-scope.js.map +1 -0
- package/dist/checks/deployment/server-banner.d.ts +4 -0
- package/dist/checks/deployment/server-banner.d.ts.map +1 -0
- package/dist/checks/deployment/server-banner.js +60 -0
- package/dist/checks/deployment/server-banner.js.map +1 -0
- package/dist/checks/deployment/trace.d.ts +3 -0
- package/dist/checks/deployment/trace.d.ts.map +1 -0
- package/dist/checks/deployment/trace.js +30 -0
- package/dist/checks/deployment/trace.js.map +1 -0
- package/dist/checks/headers/clickjacking.d.ts +5 -0
- package/dist/checks/headers/clickjacking.d.ts.map +1 -0
- package/dist/checks/headers/clickjacking.js +57 -0
- package/dist/checks/headers/clickjacking.js.map +1 -0
- package/dist/checks/headers/content-type-options.d.ts +3 -0
- package/dist/checks/headers/content-type-options.d.ts.map +1 -0
- package/dist/checks/headers/content-type-options.js +17 -0
- package/dist/checks/headers/content-type-options.js.map +1 -0
- package/dist/checks/headers/cors.d.ts +4 -0
- package/dist/checks/headers/cors.d.ts.map +1 -0
- package/dist/checks/headers/cors.js +38 -0
- package/dist/checks/headers/cors.js.map +1 -0
- package/dist/checks/html.d.ts +11 -0
- package/dist/checks/html.d.ts.map +1 -0
- package/dist/checks/html.js +30 -0
- package/dist/checks/html.js.map +1 -0
- package/dist/checks/index.d.ts +7 -0
- package/dist/checks/index.d.ts.map +1 -0
- package/dist/checks/index.js +48 -0
- package/dist/checks/index.js.map +1 -0
- package/dist/checks/info-disclosure/directory-listing.d.ts +6 -0
- package/dist/checks/info-disclosure/directory-listing.d.ts.map +1 -0
- package/dist/checks/info-disclosure/directory-listing.js +60 -0
- package/dist/checks/info-disclosure/directory-listing.js.map +1 -0
- package/dist/checks/info-disclosure/exposed-files.d.ts +4 -0
- package/dist/checks/info-disclosure/exposed-files.d.ts.map +1 -0
- package/dist/checks/info-disclosure/exposed-files.js +56 -0
- package/dist/checks/info-disclosure/exposed-files.js.map +1 -0
- package/dist/checks/info-disclosure/more.d.ts +8 -0
- package/dist/checks/info-disclosure/more.d.ts.map +1 -0
- package/dist/checks/info-disclosure/more.js +186 -0
- package/dist/checks/info-disclosure/more.js.map +1 -0
- package/dist/checks/tls/certificate.d.ts +3 -0
- package/dist/checks/tls/certificate.d.ts.map +1 -0
- package/dist/checks/tls/certificate.js +49 -0
- package/dist/checks/tls/certificate.js.map +1 -0
- package/dist/checks/tls/hsts.d.ts +5 -0
- package/dist/checks/tls/hsts.d.ts.map +1 -0
- package/dist/checks/tls/hsts.js +35 -0
- package/dist/checks/tls/hsts.js.map +1 -0
- package/dist/checks/tls/https-redirect.d.ts +3 -0
- package/dist/checks/tls/https-redirect.d.ts.map +1 -0
- package/dist/checks/tls/https-redirect.js +46 -0
- package/dist/checks/tls/https-redirect.js.map +1 -0
- package/dist/checks/tls/legacy-protocols.d.ts +3 -0
- package/dist/checks/tls/legacy-protocols.d.ts.map +1 -0
- package/dist/checks/tls/legacy-protocols.js +27 -0
- package/dist/checks/tls/legacy-protocols.js.map +1 -0
- package/dist/checks/util.d.ts +22 -0
- package/dist/checks/util.d.ts.map +1 -0
- package/dist/checks/util.js +63 -0
- package/dist/checks/util.js.map +1 -0
- package/dist/code/checks/crypto.d.ts +5 -0
- package/dist/code/checks/crypto.d.ts.map +1 -0
- package/dist/code/checks/crypto.js +100 -0
- package/dist/code/checks/crypto.js.map +1 -0
- package/dist/code/checks/django.d.ts +14 -0
- package/dist/code/checks/django.d.ts.map +1 -0
- package/dist/code/checks/django.js +313 -0
- package/dist/code/checks/django.js.map +1 -0
- package/dist/code/checks/flask.d.ts +6 -0
- package/dist/code/checks/flask.d.ts.map +1 -0
- package/dist/code/checks/flask.js +100 -0
- package/dist/code/checks/flask.js.map +1 -0
- package/dist/code/checks/index.d.ts +9 -0
- package/dist/code/checks/index.d.ts.map +1 -0
- package/dist/code/checks/index.js +126 -0
- package/dist/code/checks/index.js.map +1 -0
- package/dist/code/checks/injection.d.ts +27 -0
- package/dist/code/checks/injection.d.ts.map +1 -0
- package/dist/code/checks/injection.js +189 -0
- package/dist/code/checks/injection.js.map +1 -0
- package/dist/code/checks/javascript-config.d.ts +14 -0
- package/dist/code/checks/javascript-config.d.ts.map +1 -0
- package/dist/code/checks/javascript-config.js +251 -0
- package/dist/code/checks/javascript-config.js.map +1 -0
- package/dist/code/checks/javascript.d.ts +34 -0
- package/dist/code/checks/javascript.d.ts.map +1 -0
- package/dist/code/checks/javascript.js +333 -0
- package/dist/code/checks/javascript.js.map +1 -0
- package/dist/code/checks/php.d.ts +27 -0
- package/dist/code/checks/php.d.ts.map +1 -0
- package/dist/code/checks/php.js +433 -0
- package/dist/code/checks/php.js.map +1 -0
- package/dist/code/checks/secrets.d.ts +10 -0
- package/dist/code/checks/secrets.d.ts.map +1 -0
- package/dist/code/checks/secrets.js +140 -0
- package/dist/code/checks/secrets.js.map +1 -0
- package/dist/code/checks/shared.d.ts +25 -0
- package/dist/code/checks/shared.d.ts.map +1 -0
- package/dist/code/checks/shared.js +57 -0
- package/dist/code/checks/shared.js.map +1 -0
- package/dist/code/checks/treesitter.d.ts +15 -0
- package/dist/code/checks/treesitter.d.ts.map +1 -0
- package/dist/code/checks/treesitter.js +322 -0
- package/dist/code/checks/treesitter.js.map +1 -0
- package/dist/code/checks/xml.d.ts +9 -0
- package/dist/code/checks/xml.d.ts.map +1 -0
- package/dist/code/checks/xml.js +78 -0
- package/dist/code/checks/xml.js.map +1 -0
- package/dist/code/context.d.ts +6 -0
- package/dist/code/context.d.ts.map +1 -0
- package/dist/code/context.js +92 -0
- package/dist/code/context.js.map +1 -0
- package/dist/code/detect.d.ts +3 -0
- package/dist/code/detect.d.ts.map +1 -0
- package/dist/code/detect.js +118 -0
- package/dist/code/detect.js.map +1 -0
- package/dist/code/django/settings.d.ts +46 -0
- package/dist/code/django/settings.d.ts.map +1 -0
- package/dist/code/django/settings.js +154 -0
- package/dist/code/django/settings.js.map +1 -0
- package/dist/code/findings.d.ts +18 -0
- package/dist/code/findings.d.ts.map +1 -0
- package/dist/code/findings.js +63 -0
- package/dist/code/findings.js.map +1 -0
- package/dist/code/javascript/ast.d.ts +46 -0
- package/dist/code/javascript/ast.d.ts.map +1 -0
- package/dist/code/javascript/ast.js +166 -0
- package/dist/code/javascript/ast.js.map +1 -0
- package/dist/code/javascript/index.d.ts +3 -0
- package/dist/code/javascript/index.d.ts.map +1 -0
- package/dist/code/javascript/index.js +3 -0
- package/dist/code/javascript/index.js.map +1 -0
- package/dist/code/javascript/module.d.ts +59 -0
- package/dist/code/javascript/module.d.ts.map +1 -0
- package/dist/code/javascript/module.js +250 -0
- package/dist/code/javascript/module.js.map +1 -0
- package/dist/code/php/index.d.ts +92 -0
- package/dist/code/php/index.d.ts.map +1 -0
- package/dist/code/php/index.js +316 -0
- package/dist/code/php/index.js.map +1 -0
- package/dist/code/project.d.ts +13 -0
- package/dist/code/project.d.ts.map +1 -0
- package/dist/code/project.js +69 -0
- package/dist/code/project.js.map +1 -0
- package/dist/code/python/ast.d.ts +47 -0
- package/dist/code/python/ast.d.ts.map +1 -0
- package/dist/code/python/ast.js +193 -0
- package/dist/code/python/ast.js.map +1 -0
- package/dist/code/python/index.d.ts +3 -0
- package/dist/code/python/index.d.ts.map +1 -0
- package/dist/code/python/index.js +3 -0
- package/dist/code/python/index.js.map +1 -0
- package/dist/code/python/module.d.ts +55 -0
- package/dist/code/python/module.d.ts.map +1 -0
- package/dist/code/python/module.js +215 -0
- package/dist/code/python/module.js.map +1 -0
- package/dist/code/scan.d.ts +24 -0
- package/dist/code/scan.d.ts.map +1 -0
- package/dist/code/scan.js +159 -0
- package/dist/code/scan.js.map +1 -0
- package/dist/code/treesitter/index.d.ts +83 -0
- package/dist/code/treesitter/index.d.ts.map +1 -0
- package/dist/code/treesitter/index.js +243 -0
- package/dist/code/treesitter/index.js.map +1 -0
- package/dist/code/types.d.ts +48 -0
- package/dist/code/types.d.ts.map +1 -0
- package/dist/code/types.js +2 -0
- package/dist/code/types.js.map +1 -0
- package/dist/content/en.d.ts +3 -0
- package/dist/content/en.d.ts.map +1 -0
- package/dist/content/en.js +722 -0
- package/dist/content/en.js.map +1 -0
- package/dist/content/index.d.ts +15 -0
- package/dist/content/index.d.ts.map +1 -0
- package/dist/content/index.js +21 -0
- package/dist/content/index.js.map +1 -0
- package/dist/content/types.d.ts +87 -0
- package/dist/content/types.d.ts.map +1 -0
- package/dist/content/types.js +2 -0
- package/dist/content/types.js.map +1 -0
- package/dist/engine.d.ts +52 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +120 -0
- package/dist/engine.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/meta.d.ts +4 -0
- package/dist/meta.d.ts.map +1 -0
- package/dist/meta.js +4 -0
- package/dist/meta.js.map +1 -0
- package/dist/net/context.d.ts +9 -0
- package/dist/net/context.d.ts.map +1 -0
- package/dist/net/context.js +62 -0
- package/dist/net/context.js.map +1 -0
- package/dist/net/guard.d.ts +16 -0
- package/dist/net/guard.d.ts.map +1 -0
- package/dist/net/guard.js +70 -0
- package/dist/net/guard.js.map +1 -0
- package/dist/net/http.d.ts +22 -0
- package/dist/net/http.d.ts.map +1 -0
- package/dist/net/http.js +114 -0
- package/dist/net/http.js.map +1 -0
- package/dist/net/tls.d.ts +15 -0
- package/dist/net/tls.d.ts.map +1 -0
- package/dist/net/tls.js +103 -0
- package/dist/net/tls.js.map +1 -0
- package/dist/report/html.d.ts +14 -0
- package/dist/report/html.d.ts.map +1 -0
- package/dist/report/html.js +210 -0
- package/dist/report/html.js.map +1 -0
- package/dist/report/index.d.ts +10 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +10 -0
- package/dist/report/index.js.map +1 -0
- package/dist/report/manual.d.ts +62 -0
- package/dist/report/manual.d.ts.map +1 -0
- package/dist/report/manual.js +190 -0
- package/dist/report/manual.js.map +1 -0
- package/dist/report/merge.d.ts +8 -0
- package/dist/report/merge.d.ts.map +1 -0
- package/dist/report/merge.js +135 -0
- package/dist/report/merge.js.map +1 -0
- package/dist/report/summary.d.ts +10 -0
- package/dist/report/summary.d.ts.map +1 -0
- package/dist/report/summary.js +27 -0
- package/dist/report/summary.js.map +1 -0
- package/dist/report/validate.d.ts +3 -0
- package/dist/report/validate.d.ts.map +1 -0
- package/dist/report/validate.js +78 -0
- package/dist/report/validate.js.map +1 -0
- package/dist/types.d.ts +244 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +4 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +24 -0
- package/dist/validate.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-banner.js","sourceRoot":"","sources":["../../../src/checks/deployment/server-banner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../../src/checks/deployment/trace.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAK5C,eAAO,MAAM,WAAW,EAAE,KA0BzB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { effectiveOrigin } from "../util.js";
|
|
3
|
+
const MARKER_HEADER = "x-insa-check-trace";
|
|
4
|
+
export const traceMethod = {
|
|
5
|
+
key: "http-trace",
|
|
6
|
+
kind: "url",
|
|
7
|
+
async run(ctx) {
|
|
8
|
+
const origin = await effectiveOrigin(ctx);
|
|
9
|
+
const enabled = [];
|
|
10
|
+
const evidence = [];
|
|
11
|
+
for (const method of ["TRACE", "TRACK"]) {
|
|
12
|
+
const marker = randomBytes(8).toString("hex");
|
|
13
|
+
const res = await ctx.request(`${origin}/`, {
|
|
14
|
+
method,
|
|
15
|
+
followRedirects: false,
|
|
16
|
+
headers: { [MARKER_HEADER]: marker },
|
|
17
|
+
});
|
|
18
|
+
evidence.push(`${method} / → HTTP ${res.status}`);
|
|
19
|
+
// Only an echo of our request proves the method is live (some apps answer 200 to any verb).
|
|
20
|
+
const echoed = res.body.includes(marker) || res.body.startsWith(`${method} /`);
|
|
21
|
+
if (res.status >= 200 && res.status < 300 && echoed)
|
|
22
|
+
enabled.push(method);
|
|
23
|
+
}
|
|
24
|
+
if (enabled.length > 0) {
|
|
25
|
+
return { status: "fail", detail: `${enabled.join(" and ")} enabled: the request is echoed back.`, evidence };
|
|
26
|
+
}
|
|
27
|
+
return { status: "pass", detail: "TRACE and TRACK are not enabled (request not echoed).", evidence };
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=trace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.js","sourceRoot":"","sources":["../../../src/checks/deployment/trace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,aAAa,GAAG,oBAAoB,CAAC;AAE3C,MAAM,CAAC,MAAM,WAAW,GAAU;IAChC,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,KAAK;IACX,KAAK,CAAC,GAAG,CAAC,GAAG;QACX,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,KAAK,MAAM,MAAM,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;YACxC,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC9C,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,EAAE;gBAC1C,MAAM;gBACN,eAAe,EAAE,KAAK;gBACtB,OAAO,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE;aACrC,CAAC,CAAC;YACH,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YAClD,4FAA4F;YAC5F,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC;YAC/E,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,MAAM;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5E,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,uCAAuC,EAAE,QAAQ,EAAE,CAAC;QAC/G,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,uDAAuD,EAAE,QAAQ,EAAE,CAAC;IACvG,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Check } from "../../types.js";
|
|
2
|
+
export declare const clickjacking: Check;
|
|
3
|
+
/** Returns a CSP directive's value ("" if present but empty), or undefined if absent. */
|
|
4
|
+
export declare function cspDirective(policy: string, name: string): string | undefined;
|
|
5
|
+
//# sourceMappingURL=clickjacking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickjacking.d.ts","sourceRoot":"","sources":["../../../src/checks/headers/clickjacking.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAG5C,eAAO,MAAM,YAAY,EAAE,KA+C1B,CAAC;AAEF,yFAAyF;AACzF,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAM7E"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { landingPage } from "../util.js";
|
|
2
|
+
export const clickjacking = {
|
|
3
|
+
key: "anti-clickjacking",
|
|
4
|
+
kind: "url",
|
|
5
|
+
async run(ctx) {
|
|
6
|
+
const res = await landingPage(ctx);
|
|
7
|
+
const csp = res.headers["content-security-policy"];
|
|
8
|
+
const xfo = res.headers["x-frame-options"];
|
|
9
|
+
const evidence = [
|
|
10
|
+
csp ? `Content-Security-Policy: ${csp}` : null,
|
|
11
|
+
xfo ? `X-Frame-Options: ${xfo}` : null,
|
|
12
|
+
].filter((e) => e !== null);
|
|
13
|
+
// CSP frame-ancestors takes precedence over X-Frame-Options in modern browsers.
|
|
14
|
+
// Multiple CSP headers are comma-joined; a frame-ancestors in any of them restricts framing.
|
|
15
|
+
const ancestors = csp
|
|
16
|
+
?.split(",")
|
|
17
|
+
.map((policy) => cspDirective(policy, "frame-ancestors"))
|
|
18
|
+
.find((v) => v !== undefined);
|
|
19
|
+
if (ancestors !== undefined) {
|
|
20
|
+
const sources = ancestors.split(/\s+/).filter(Boolean);
|
|
21
|
+
const permissive = sources.some((s) => s === "*" || /^(https?|wss?):?$/i.test(s));
|
|
22
|
+
if (permissive) {
|
|
23
|
+
return { status: "fail", detail: `CSP frame-ancestors allows any site to frame the page ("${ancestors}").`, evidence };
|
|
24
|
+
}
|
|
25
|
+
return { status: "pass", detail: `Framing restricted by CSP frame-ancestors ${ancestors || "(none)"}.`, evidence };
|
|
26
|
+
}
|
|
27
|
+
if (!xfo) {
|
|
28
|
+
return {
|
|
29
|
+
status: "fail",
|
|
30
|
+
detail: "Neither X-Frame-Options nor CSP frame-ancestors is set; the page can be framed.",
|
|
31
|
+
evidence,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const values = xfo.split(",").map((v) => v.trim().toUpperCase());
|
|
35
|
+
if (values.every((v) => v === "DENY" || v === "SAMEORIGIN")) {
|
|
36
|
+
return { status: "pass", detail: `X-Frame-Options: ${values[0]}.`, evidence };
|
|
37
|
+
}
|
|
38
|
+
if (values.some((v) => v.startsWith("ALLOW-FROM"))) {
|
|
39
|
+
return {
|
|
40
|
+
status: "fail",
|
|
41
|
+
detail: "X-Frame-Options ALLOW-FROM is ignored by modern browsers; use CSP frame-ancestors.",
|
|
42
|
+
evidence,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return { status: "fail", detail: `X-Frame-Options value "${xfo}" is invalid.`, evidence };
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
/** Returns a CSP directive's value ("" if present but empty), or undefined if absent. */
|
|
49
|
+
export function cspDirective(policy, name) {
|
|
50
|
+
for (const part of policy.split(";")) {
|
|
51
|
+
const [directive, ...sources] = part.trim().split(/\s+/);
|
|
52
|
+
if (directive?.toLowerCase() === name)
|
|
53
|
+
return sources.join(" ");
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=clickjacking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickjacking.js","sourceRoot":"","sources":["../../../src/checks/headers/clickjacking.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-type-options.d.ts","sourceRoot":"","sources":["../../../src/checks/headers/content-type-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAG5C,eAAO,MAAM,kBAAkB,EAAE,KAchC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { landingPage } from "../util.js";
|
|
2
|
+
export const contentTypeOptions = {
|
|
3
|
+
key: "x-content-type-options",
|
|
4
|
+
kind: "url",
|
|
5
|
+
async run(ctx) {
|
|
6
|
+
const res = await landingPage(ctx);
|
|
7
|
+
const value = res.headers["x-content-type-options"];
|
|
8
|
+
if (!value) {
|
|
9
|
+
return { status: "fail", detail: "X-Content-Type-Options header is missing." };
|
|
10
|
+
}
|
|
11
|
+
if (value.trim().toLowerCase() !== "nosniff") {
|
|
12
|
+
return { status: "fail", detail: `X-Content-Type-Options is "${value}", expected "nosniff".`, evidence: [value] };
|
|
13
|
+
}
|
|
14
|
+
return { status: "pass", detail: "X-Content-Type-Options: nosniff is set.", evidence: [value] };
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=content-type-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-type-options.js","sourceRoot":"","sources":["../../../src/checks/headers/content-type-options.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,CAAC,MAAM,kBAAkB,GAAU;IACvC,GAAG,EAAE,wBAAwB;IAC7B,IAAI,EAAE,KAAK;IACX,KAAK,CAAC,GAAG,CAAC,GAAG;QACX,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;QACpD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,2CAA2C,EAAE,CAAC;QACjF,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,SAAS,EAAE,CAAC;YAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,8BAA8B,KAAK,wBAAwB,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;QACpH,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,yCAAyC,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;IAClG,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../../src/checks/headers/cors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAM5C,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,EAAE,KA8B/B,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { effectiveOrigin, landingPage } from "../util.js";
|
|
2
|
+
/** An origin that cannot exist, to see whether the server reflects arbitrary origins. */
|
|
3
|
+
const PROBE_ORIGIN = "https://insa-check-origin.invalid";
|
|
4
|
+
/** #98 Insecure cross-domain access policy (CORS, Flash/Silverlight policy files). */
|
|
5
|
+
export const crossDomainPolicy = {
|
|
6
|
+
key: "cross-domain-policy",
|
|
7
|
+
kind: "url",
|
|
8
|
+
async run(ctx) {
|
|
9
|
+
const origin = await effectiveOrigin(ctx);
|
|
10
|
+
const page = await landingPage(ctx);
|
|
11
|
+
const res = await ctx.request(page.url, { headers: { origin: PROBE_ORIGIN } });
|
|
12
|
+
const acao = res.headers["access-control-allow-origin"];
|
|
13
|
+
const credentials = (res.headers["access-control-allow-credentials"] ?? "").toLowerCase() === "true";
|
|
14
|
+
const problems = [];
|
|
15
|
+
const review = [];
|
|
16
|
+
if (acao === PROBE_ORIGIN || acao === "null") {
|
|
17
|
+
(credentials ? problems : review).push(`Access-Control-Allow-Origin reflects any origin (${acao})${credentials ? " and allows credentials: other sites can read authenticated responses" : ""}`);
|
|
18
|
+
}
|
|
19
|
+
else if (acao === "*" && credentials) {
|
|
20
|
+
problems.push("Access-Control-Allow-Origin: * is combined with Allow-Credentials: true");
|
|
21
|
+
}
|
|
22
|
+
const flash = await ctx.request(`${origin}/crossdomain.xml`, { followRedirects: false });
|
|
23
|
+
if (flash.status === 200 && /<allow-access-from[^>]+domain\s*=\s*["']\*["']/i.test(flash.body))
|
|
24
|
+
problems.push("/crossdomain.xml allows access from any domain");
|
|
25
|
+
const silverlight = await ctx.request(`${origin}/clientaccesspolicy.xml`, { followRedirects: false });
|
|
26
|
+
if (silverlight.status === 200 && /<domain[^>]+uri\s*=\s*["']\*["']/i.test(silverlight.body))
|
|
27
|
+
problems.push("/clientaccesspolicy.xml allows access from any domain");
|
|
28
|
+
if (problems.length)
|
|
29
|
+
return { status: "fail", detail: `${problems.length} insecure cross-domain setting(s).`, evidence: problems };
|
|
30
|
+
if (review.length)
|
|
31
|
+
return { status: "manual", detail: "Any origin may read responses (without credentials). Acceptable only for fully public data.", evidence: review };
|
|
32
|
+
return {
|
|
33
|
+
status: "pass",
|
|
34
|
+
detail: acao === "*" ? "CORS allows any origin without credentials (public data only); no permissive policy files." : "No permissive CORS headers or cross-domain policy files found.",
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=cors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.js","sourceRoot":"","sources":["../../../src/checks/headers/cors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE1D,yFAAyF;AACzF,MAAM,YAAY,GAAG,mCAAmC,CAAC;AAEzD,sFAAsF;AACtF,MAAM,CAAC,MAAM,iBAAiB,GAAU;IACtC,GAAG,EAAE,qBAAqB;IAC1B,IAAI,EAAE,KAAK;IACX,KAAK,CAAC,GAAG,CAAC,GAAG;QACX,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;QAC/E,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAC;QACxD,MAAM,WAAW,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,kCAAkC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC;QACrG,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YAC7C,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CACpC,oDAAoD,IAAI,IAAI,WAAW,CAAC,CAAC,CAAC,uEAAuE,CAAC,CAAC,CAAC,EAAE,EAAE,CACzJ,CAAC;QACJ,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC;YACvC,QAAQ,CAAC,IAAI,CAAC,yEAAyE,CAAC,CAAC;QAC3F,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,GAAG,MAAM,kBAAkB,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,CAAC;QACzF,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,IAAI,iDAAiD,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;QAChK,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,GAAG,MAAM,yBAAyB,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,CAAC;QACtG,IAAI,WAAW,CAAC,MAAM,KAAK,GAAG,IAAI,mCAAmC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;QAErK,IAAI,QAAQ,CAAC,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,oCAAoC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;QACnI,IAAI,MAAM,CAAC,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,6FAA6F,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QACxK,OAAO;YACL,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,4FAA4F,CAAC,CAAC,CAAC,gEAAgE;SACvL,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Minimal HTML helpers for passive checks. Regex-based: good enough to read attributes, not a full parser. */
|
|
2
|
+
export interface Tag {
|
|
3
|
+
name: string;
|
|
4
|
+
attrs: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
/** Opening tags of the given names with their attributes (names lower-cased; valueless attributes = ""). */
|
|
7
|
+
export declare function findTags(html: string, names: string[]): Tag[];
|
|
8
|
+
export declare function htmlComments(html: string): string[];
|
|
9
|
+
/** Resolves a possibly relative URL; undefined if it cannot be parsed or is not http(s). */
|
|
10
|
+
export declare function resolveUrl(value: string | undefined, base: string): URL | undefined;
|
|
11
|
+
//# sourceMappingURL=html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/checks/html.ts"],"names":[],"mappings":"AAAA,+GAA+G;AAE/G,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,4GAA4G;AAC5G,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAG,EAAE,CAW7D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEnD;AAED,4FAA4F;AAC5F,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAQnF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Minimal HTML helpers for passive checks. Regex-based: good enough to read attributes, not a full parser. */
|
|
2
|
+
/** Opening tags of the given names with their attributes (names lower-cased; valueless attributes = ""). */
|
|
3
|
+
export function findTags(html, names) {
|
|
4
|
+
const out = [];
|
|
5
|
+
const tagRe = new RegExp(`<(${names.join("|")})\\b([^>]*)>`, "gi");
|
|
6
|
+
for (const m of html.matchAll(tagRe)) {
|
|
7
|
+
const attrs = {};
|
|
8
|
+
for (const a of (m[2] ?? "").matchAll(/([\w:-]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+)))?/g)) {
|
|
9
|
+
attrs[a[1].toLowerCase()] = a[2] ?? a[3] ?? a[4] ?? "";
|
|
10
|
+
}
|
|
11
|
+
out.push({ name: m[1].toLowerCase(), attrs });
|
|
12
|
+
}
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
15
|
+
export function htmlComments(html) {
|
|
16
|
+
return [...html.matchAll(/<!--([\s\S]*?)-->/g)].map((m) => m[1].trim());
|
|
17
|
+
}
|
|
18
|
+
/** Resolves a possibly relative URL; undefined if it cannot be parsed or is not http(s). */
|
|
19
|
+
export function resolveUrl(value, base) {
|
|
20
|
+
if (!value)
|
|
21
|
+
return undefined;
|
|
22
|
+
try {
|
|
23
|
+
const url = new URL(value, base);
|
|
24
|
+
return url.protocol === "http:" || url.protocol === "https:" ? url : undefined;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/checks/html.ts"],"names":[],"mappings":"AAAA,+GAA+G;AAO/G,4GAA4G;AAC5G,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,KAAe;IACpD,MAAM,GAAG,GAAU,EAAE,CAAC;IACtB,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IACnE,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,KAAK,GAA2B,EAAE,CAAC;QACzC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,2DAA2D,CAAC,EAAE,CAAC;YACnG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1D,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AAC3E,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,UAAU,CAAC,KAAyB,EAAE,IAAY;IAChE,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACjC,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IACjF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Check } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* All automated checks, keyed by Check.key. Annex B items opt in via AnnexItem.check.
|
|
4
|
+
* Tier 2 (code scanning) and Tier 3 (assisted manual) checks register here too.
|
|
5
|
+
*/
|
|
6
|
+
export declare const CHECKS: ReadonlyMap<string, Check>;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/checks/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAiBzC;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,KAAK,CA6B7C,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { cookieHttpOnly, cookieSecure } from "./cookies/cookie-flags.js";
|
|
2
|
+
import { charset, contentType, insecureForms, mixedContent, thirdPartyContent } from "./content/page.js";
|
|
3
|
+
import { cookieDomain, cookiePath } from "./cookies/cookie-scope.js";
|
|
4
|
+
import { serverBanner } from "./deployment/server-banner.js";
|
|
5
|
+
import { traceMethod } from "./deployment/trace.js";
|
|
6
|
+
import { crossDomainPolicy } from "./headers/cors.js";
|
|
7
|
+
import { archivedPages, debugPages, errorMessages, internalAddresses, pageSource, robotsTxt } from "./info-disclosure/more.js";
|
|
8
|
+
import { clickjacking } from "./headers/clickjacking.js";
|
|
9
|
+
import { contentTypeOptions } from "./headers/content-type-options.js";
|
|
10
|
+
import { directoryListing } from "./info-disclosure/directory-listing.js";
|
|
11
|
+
import { exposedFiles } from "./info-disclosure/exposed-files.js";
|
|
12
|
+
import { certificate } from "./tls/certificate.js";
|
|
13
|
+
import { hsts } from "./tls/hsts.js";
|
|
14
|
+
import { httpsRedirect } from "./tls/https-redirect.js";
|
|
15
|
+
import { legacyProtocols } from "./tls/legacy-protocols.js";
|
|
16
|
+
/**
|
|
17
|
+
* All automated checks, keyed by Check.key. Annex B items opt in via AnnexItem.check.
|
|
18
|
+
* Tier 2 (code scanning) and Tier 3 (assisted manual) checks register here too.
|
|
19
|
+
*/
|
|
20
|
+
export const CHECKS = new Map([
|
|
21
|
+
httpsRedirect,
|
|
22
|
+
hsts,
|
|
23
|
+
certificate,
|
|
24
|
+
legacyProtocols,
|
|
25
|
+
contentTypeOptions,
|
|
26
|
+
clickjacking,
|
|
27
|
+
cookieSecure,
|
|
28
|
+
cookieHttpOnly,
|
|
29
|
+
traceMethod,
|
|
30
|
+
exposedFiles,
|
|
31
|
+
directoryListing,
|
|
32
|
+
debugPages,
|
|
33
|
+
errorMessages,
|
|
34
|
+
robotsTxt,
|
|
35
|
+
pageSource,
|
|
36
|
+
internalAddresses,
|
|
37
|
+
archivedPages,
|
|
38
|
+
thirdPartyContent,
|
|
39
|
+
insecureForms,
|
|
40
|
+
mixedContent,
|
|
41
|
+
cookieDomain,
|
|
42
|
+
cookiePath,
|
|
43
|
+
contentType,
|
|
44
|
+
charset,
|
|
45
|
+
serverBanner,
|
|
46
|
+
crossDomainPolicy,
|
|
47
|
+
].map((c) => [c.key, c]));
|
|
48
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/checks/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACzG,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC/H,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAA+B,IAAI,GAAG,CACvD;IACE,aAAa;IACb,IAAI;IACJ,WAAW;IACX,eAAe;IACf,kBAAkB;IAClB,YAAY;IACZ,YAAY;IACZ,cAAc;IACd,WAAW;IACX,YAAY;IACZ,gBAAgB;IAChB,UAAU;IACV,aAAa;IACb,SAAS;IACT,UAAU;IACV,iBAAiB;IACjB,aAAa;IACb,iBAAiB;IACjB,aAAa;IACb,YAAY;IACZ,YAAY;IACZ,UAAU;IACV,WAAW;IACX,OAAO;IACP,YAAY;IACZ,iBAAiB;CAClB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CACzB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Check } from "../../types.js";
|
|
2
|
+
export declare function isDirectoryListing(body: string): boolean;
|
|
3
|
+
/** Parent directories of same-origin resources referenced by the page, e.g. /static/js/app.js -> /static/js/, /static/. */
|
|
4
|
+
export declare function directoriesFromHtml(html: string, pageUrl: string): string[];
|
|
5
|
+
export declare const directoryListing: Check;
|
|
6
|
+
//# sourceMappingURL=directory-listing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-listing.d.ts","sourceRoot":"","sources":["../../../src/checks/info-disclosure/directory-listing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAc5C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,2HAA2H;AAC3H,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAiB3E;AAED,eAAO,MAAM,gBAAgB,EAAE,KA0B9B,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { landingPage } from "../util.js";
|
|
2
|
+
const COMMON_DIRS = ["/images/", "/img/", "/uploads/", "/assets/", "/static/", "/css/", "/js/", "/files/"];
|
|
3
|
+
const MAX_PROBES = 12;
|
|
4
|
+
const LISTING_SIGNATURES = [
|
|
5
|
+
/<title>\s*Index of \//i, // Apache, nginx autoindex
|
|
6
|
+
/<h1>\s*Index of \//i,
|
|
7
|
+
/Directory listing for \//i, // Python http.server
|
|
8
|
+
/<title>\s*Directory Listing For/i, // Tomcat
|
|
9
|
+
/\[To Parent Directory\]/i, // IIS
|
|
10
|
+
];
|
|
11
|
+
export function isDirectoryListing(body) {
|
|
12
|
+
return LISTING_SIGNATURES.some((re) => re.test(body));
|
|
13
|
+
}
|
|
14
|
+
/** Parent directories of same-origin resources referenced by the page, e.g. /static/js/app.js -> /static/js/, /static/. */
|
|
15
|
+
export function directoriesFromHtml(html, pageUrl) {
|
|
16
|
+
const base = new URL(pageUrl);
|
|
17
|
+
const dirs = new Set();
|
|
18
|
+
for (const match of html.matchAll(/(?:src|href)\s*=\s*["']([^"'#?]+)/gi)) {
|
|
19
|
+
let url;
|
|
20
|
+
try {
|
|
21
|
+
url = new URL(match[1], base);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (url.origin !== base.origin)
|
|
27
|
+
continue;
|
|
28
|
+
const segments = url.pathname.split("/").slice(1, -1);
|
|
29
|
+
for (let i = segments.length; i > 0; i--) {
|
|
30
|
+
dirs.add(`/${segments.slice(0, i).join("/")}/`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return [...dirs];
|
|
34
|
+
}
|
|
35
|
+
export const directoryListing = {
|
|
36
|
+
key: "directory-listing",
|
|
37
|
+
kind: "url",
|
|
38
|
+
async run(ctx) {
|
|
39
|
+
const page = await landingPage(ctx);
|
|
40
|
+
const origin = new URL(page.url).origin;
|
|
41
|
+
const candidates = [...new Set([...directoriesFromHtml(page.body, page.url), ...COMMON_DIRS])].slice(0, MAX_PROBES);
|
|
42
|
+
const listed = [];
|
|
43
|
+
if (isDirectoryListing(page.body))
|
|
44
|
+
listed.push(page.url);
|
|
45
|
+
await Promise.all(candidates.map(async (dir) => {
|
|
46
|
+
const res = await ctx.request(`${origin}${dir}`);
|
|
47
|
+
if (res.status === 200 && isDirectoryListing(res.body))
|
|
48
|
+
listed.push(`${origin}${dir}`);
|
|
49
|
+
}));
|
|
50
|
+
if (listed.length > 0) {
|
|
51
|
+
return { status: "fail", detail: `Directory listing is enabled on ${listed.length} path(s).`, evidence: listed.sort() };
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
status: "pass",
|
|
55
|
+
detail: `No directory listing found on ${candidates.length + 1} paths checked.`,
|
|
56
|
+
evidence: candidates,
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=directory-listing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-listing.js","sourceRoot":"","sources":["../../../src/checks/info-disclosure/directory-listing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exposed-files.d.ts","sourceRoot":"","sources":["../../../src/checks/info-disclosure/exposed-files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAgD5C,eAAO,MAAM,kBAAkB,UAA4B,CAAC;AAE5D,eAAO,MAAM,YAAY,EAAE,KAmB1B,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { effectiveOrigin } from "../util.js";
|
|
2
|
+
const PROBES = [
|
|
3
|
+
{
|
|
4
|
+
path: "/.git/HEAD",
|
|
5
|
+
matches: (b) => /^(ref: refs\/|[0-9a-f]{40}\s*$)/.test(b),
|
|
6
|
+
describe: () => "Git repository metadata (HEAD) is downloadable",
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
path: "/.git/config",
|
|
10
|
+
matches: (b) => /^\s*\[core\]/m.test(b),
|
|
11
|
+
describe: () => "Git repository config is downloadable",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
path: "/.env",
|
|
15
|
+
matches: (b) => !/^\s*</.test(b) && envAssignments(b) >= 2,
|
|
16
|
+
describe: (b) => `Environment file with ${envAssignments(b)} variable assignments (values not shown)`,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
path: "/.svn/wc.db",
|
|
20
|
+
matches: (b) => b.startsWith("SQLite format 3"),
|
|
21
|
+
describe: () => "Subversion working-copy database is downloadable",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
path: "/.DS_Store",
|
|
25
|
+
matches: (b) => b.slice(0, 8).includes("Bud1"),
|
|
26
|
+
describe: () => "macOS .DS_Store (reveals file names) is downloadable",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
path: "/.htpasswd",
|
|
30
|
+
matches: (b) => !/^\s*</.test(b) && /^[^:\s]+:(\$|\{SHA\}|[./0-9A-Za-z]{13}$)/m.test(b),
|
|
31
|
+
describe: () => "Password hash file .htpasswd is downloadable",
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
function envAssignments(body) {
|
|
35
|
+
return body.split("\n").filter((line) => /^\s*(export\s+)?[A-Za-z_][A-Za-z0-9_]*\s*=/.test(line)).length;
|
|
36
|
+
}
|
|
37
|
+
export const EXPOSED_FILE_PATHS = PROBES.map((p) => p.path);
|
|
38
|
+
export const exposedFiles = {
|
|
39
|
+
key: "exposed-files",
|
|
40
|
+
kind: "url",
|
|
41
|
+
async run(ctx) {
|
|
42
|
+
const origin = await effectiveOrigin(ctx);
|
|
43
|
+
const findings = [];
|
|
44
|
+
await Promise.all(PROBES.map(async (probe) => {
|
|
45
|
+
const res = await ctx.request(`${origin}${probe.path}`, { followRedirects: false });
|
|
46
|
+
if (res.status === 200 && probe.matches(res.body)) {
|
|
47
|
+
findings.push(`${origin}${probe.path}: ${probe.describe(res.body)}`);
|
|
48
|
+
}
|
|
49
|
+
}));
|
|
50
|
+
if (findings.length > 0) {
|
|
51
|
+
return { status: "fail", detail: `${findings.length} sensitive file(s) are publicly accessible.`, evidence: findings.sort() };
|
|
52
|
+
}
|
|
53
|
+
return { status: "pass", detail: `None of ${EXPOSED_FILE_PATHS.join(", ")} are exposed.` };
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=exposed-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exposed-files.js","sourceRoot":"","sources":["../../../src/checks/info-disclosure/exposed-files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Check } from "../../types.js";
|
|
2
|
+
export declare const debugPages: Check;
|
|
3
|
+
export declare const errorMessages: Check;
|
|
4
|
+
export declare const robotsTxt: Check;
|
|
5
|
+
export declare const pageSource: Check;
|
|
6
|
+
export declare const internalAddresses: Check;
|
|
7
|
+
export declare const archivedPages: Check;
|
|
8
|
+
//# sourceMappingURL=more.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"more.d.ts","sourceRoot":"","sources":["../../../src/checks/info-disclosure/more.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAsB5C,eAAO,MAAM,UAAU,EAAE,KAexB,CAAC;AAgBF,eAAO,MAAM,aAAa,EAAE,KAgB3B,CAAC;AAMF,eAAO,MAAM,SAAS,EAAE,KAoBvB,CAAC;AAoBF,eAAO,MAAM,UAAU,EAAE,KA6BxB,CAAC;AAMF,eAAO,MAAM,iBAAiB,EAAE,KAmB/B,CAAC;AAGF,eAAO,MAAM,aAAa,EAAE,KAY3B,CAAC"}
|