@node9/policy-engine 2.9.2 → 2.9.3
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/dist/index.js +11 -5
- package/dist/index.mjs +11 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2866,9 +2866,15 @@ var METADATA_ADDRESSES = /* @__PURE__ */ new Set([
|
|
|
2866
2866
|
// AWS ECS task role
|
|
2867
2867
|
"168.63.129.16",
|
|
2868
2868
|
// Azure WireServer
|
|
2869
|
-
"fd00:ec2::254"
|
|
2869
|
+
"fd00:ec2::254",
|
|
2870
2870
|
// AWS IMDS over IPv6 (inside fc00::/7, which is NOT a tier)
|
|
2871
|
+
// Alibaba Cloud IMDS. It sits INSIDE 100.64/10, so before this line it was
|
|
2872
|
+
// classified as cgnat and therefore exemptable: one ssrfAllow entry opened a
|
|
2873
|
+
// live credential endpoint. It has to be named here, above the range check,
|
|
2874
|
+
// and it is the reason relaxing cgnat is safe.
|
|
2875
|
+
"100.100.100.200"
|
|
2871
2876
|
]);
|
|
2877
|
+
var STRICT_TIERS = /* @__PURE__ */ new Set(["private", "unspecified", "cgnat"]);
|
|
2872
2878
|
var METADATA_HOSTNAMES = /* @__PURE__ */ new Set(["metadata.google.internal", "metadata.goog", "metadata"]);
|
|
2873
2879
|
var v4Octets = (a) => {
|
|
2874
2880
|
const p = a.split(".");
|
|
@@ -2891,7 +2897,7 @@ function classifySsrf(host) {
|
|
|
2891
2897
|
if (METADATA_ADDRESSES.has(ip)) return hit("metadata", false);
|
|
2892
2898
|
const o = v4Octets(ip);
|
|
2893
2899
|
if (o) {
|
|
2894
|
-
if (o[0] === 0 && o[1] === 0 && o[2] === 0 && o[3] === 0) return hit("unspecified",
|
|
2900
|
+
if (o[0] === 0 && o[1] === 0 && o[2] === 0 && o[3] === 0) return hit("unspecified", true);
|
|
2895
2901
|
if (o[0] === 169 && o[1] === 254) return hit("link-local", false);
|
|
2896
2902
|
if (o[0] >= 224 && o[0] <= 239) return hit("multicast", false);
|
|
2897
2903
|
if (o[0] === 100 && o[1] >= 64 && o[1] <= 127) return hit("cgnat", true);
|
|
@@ -2903,7 +2909,7 @@ function classifySsrf(host) {
|
|
|
2903
2909
|
}
|
|
2904
2910
|
const g = expandIpv6(ip);
|
|
2905
2911
|
if (!g) return null;
|
|
2906
|
-
if (g.every((x) => x === 0)) return hit("unspecified",
|
|
2912
|
+
if (g.every((x) => x === 0)) return hit("unspecified", true);
|
|
2907
2913
|
if ((g[0] & 65472) === 65152) return hit("link-local", false);
|
|
2908
2914
|
if ((g[0] & 65280) === 65280) return hit("multicast", false);
|
|
2909
2915
|
if (g.slice(0, 7).every((x) => x === 0) && g[7] === 1) return hit("private", true);
|
|
@@ -2916,7 +2922,7 @@ var TIER_REASON = {
|
|
|
2916
2922
|
metadata: "a cloud instance-metadata endpoint, the classic credential-theft target",
|
|
2917
2923
|
"link-local": "a link-local address",
|
|
2918
2924
|
multicast: "a multicast address",
|
|
2919
|
-
unspecified: "the unspecified address",
|
|
2925
|
+
unspecified: "the unspecified address, which reaches this host",
|
|
2920
2926
|
cgnat: "a carrier-grade NAT address",
|
|
2921
2927
|
private: "a loopback or private address"
|
|
2922
2928
|
};
|
|
@@ -2927,7 +2933,7 @@ function ssrfFloor(tokens, opts = {}) {
|
|
|
2927
2933
|
for (const { token, binary } of tokens) {
|
|
2928
2934
|
const m = classifySsrf(token);
|
|
2929
2935
|
if (!m) continue;
|
|
2930
|
-
if (m.tier
|
|
2936
|
+
if (STRICT_TIERS.has(m.tier) && !opts.ssrfStrict) continue;
|
|
2931
2937
|
if (m.overridable && m.normalized && exempt.has(m.normalized)) continue;
|
|
2932
2938
|
return {
|
|
2933
2939
|
...m,
|
package/dist/index.mjs
CHANGED
|
@@ -2743,9 +2743,15 @@ var METADATA_ADDRESSES = /* @__PURE__ */ new Set([
|
|
|
2743
2743
|
// AWS ECS task role
|
|
2744
2744
|
"168.63.129.16",
|
|
2745
2745
|
// Azure WireServer
|
|
2746
|
-
"fd00:ec2::254"
|
|
2746
|
+
"fd00:ec2::254",
|
|
2747
2747
|
// AWS IMDS over IPv6 (inside fc00::/7, which is NOT a tier)
|
|
2748
|
+
// Alibaba Cloud IMDS. It sits INSIDE 100.64/10, so before this line it was
|
|
2749
|
+
// classified as cgnat and therefore exemptable: one ssrfAllow entry opened a
|
|
2750
|
+
// live credential endpoint. It has to be named here, above the range check,
|
|
2751
|
+
// and it is the reason relaxing cgnat is safe.
|
|
2752
|
+
"100.100.100.200"
|
|
2748
2753
|
]);
|
|
2754
|
+
var STRICT_TIERS = /* @__PURE__ */ new Set(["private", "unspecified", "cgnat"]);
|
|
2749
2755
|
var METADATA_HOSTNAMES = /* @__PURE__ */ new Set(["metadata.google.internal", "metadata.goog", "metadata"]);
|
|
2750
2756
|
var v4Octets = (a) => {
|
|
2751
2757
|
const p = a.split(".");
|
|
@@ -2768,7 +2774,7 @@ function classifySsrf(host) {
|
|
|
2768
2774
|
if (METADATA_ADDRESSES.has(ip)) return hit("metadata", false);
|
|
2769
2775
|
const o = v4Octets(ip);
|
|
2770
2776
|
if (o) {
|
|
2771
|
-
if (o[0] === 0 && o[1] === 0 && o[2] === 0 && o[3] === 0) return hit("unspecified",
|
|
2777
|
+
if (o[0] === 0 && o[1] === 0 && o[2] === 0 && o[3] === 0) return hit("unspecified", true);
|
|
2772
2778
|
if (o[0] === 169 && o[1] === 254) return hit("link-local", false);
|
|
2773
2779
|
if (o[0] >= 224 && o[0] <= 239) return hit("multicast", false);
|
|
2774
2780
|
if (o[0] === 100 && o[1] >= 64 && o[1] <= 127) return hit("cgnat", true);
|
|
@@ -2780,7 +2786,7 @@ function classifySsrf(host) {
|
|
|
2780
2786
|
}
|
|
2781
2787
|
const g = expandIpv6(ip);
|
|
2782
2788
|
if (!g) return null;
|
|
2783
|
-
if (g.every((x) => x === 0)) return hit("unspecified",
|
|
2789
|
+
if (g.every((x) => x === 0)) return hit("unspecified", true);
|
|
2784
2790
|
if ((g[0] & 65472) === 65152) return hit("link-local", false);
|
|
2785
2791
|
if ((g[0] & 65280) === 65280) return hit("multicast", false);
|
|
2786
2792
|
if (g.slice(0, 7).every((x) => x === 0) && g[7] === 1) return hit("private", true);
|
|
@@ -2793,7 +2799,7 @@ var TIER_REASON = {
|
|
|
2793
2799
|
metadata: "a cloud instance-metadata endpoint, the classic credential-theft target",
|
|
2794
2800
|
"link-local": "a link-local address",
|
|
2795
2801
|
multicast: "a multicast address",
|
|
2796
|
-
unspecified: "the unspecified address",
|
|
2802
|
+
unspecified: "the unspecified address, which reaches this host",
|
|
2797
2803
|
cgnat: "a carrier-grade NAT address",
|
|
2798
2804
|
private: "a loopback or private address"
|
|
2799
2805
|
};
|
|
@@ -2804,7 +2810,7 @@ function ssrfFloor(tokens, opts = {}) {
|
|
|
2804
2810
|
for (const { token, binary } of tokens) {
|
|
2805
2811
|
const m = classifySsrf(token);
|
|
2806
2812
|
if (!m) continue;
|
|
2807
|
-
if (m.tier
|
|
2813
|
+
if (STRICT_TIERS.has(m.tier) && !opts.ssrfStrict) continue;
|
|
2808
2814
|
if (m.overridable && m.normalized && exempt.has(m.normalized)) continue;
|
|
2809
2815
|
return {
|
|
2810
2816
|
...m,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node9/policy-engine",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.3",
|
|
4
4
|
"description": "Shared policy evaluation engine for node9 — DLP, smart rules, AST shell parsing, shields, loop detection. Pure functions, no I/O. Used by both node9-proxy and the node9 SaaS firewall.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://node9.ai",
|