ssrf-agent-guard 0.1.1 → 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/dist/index.cjs.js CHANGED
@@ -49,7 +49,7 @@ function isSafeHost(hostname, isValidDomainOptions) {
49
49
  // Case 2: Domain name
50
50
  return isValidDomain(hostname, {
51
51
  allowUnicode: false,
52
- subdomain: false,
52
+ subdomain: true,
53
53
  ...isValidDomainOptions,
54
54
  });
55
55
  }
@@ -80,7 +80,7 @@ const CREATE_CONNECTION = Symbol('createConnection');
80
80
  * @param isValidDomainOptions Options for validating domain names.
81
81
  * @returns The patched CustomAgent instance.
82
82
  */
83
- function index (url, isValidDomainOptions) {
83
+ const ssrfAgentGuard = function (url, isValidDomainOptions) {
84
84
  const finalAgent = getAgent(url);
85
85
  // Prevent patching the agent multiple times
86
86
  if (finalAgent[CREATE_CONNECTION]) {
@@ -111,7 +111,7 @@ function index (url, isValidDomainOptions) {
111
111
  }
112
112
  // Ensure resolvedAddress is a string for the check (it's typically a string for simple lookups)
113
113
  const ipToCheck = Array.isArray(resolvedAddress) ? resolvedAddress[0] : resolvedAddress;
114
- if (!isSafeIp(ipToCheck)) {
114
+ if (!isSafeHost(ipToCheck)) {
115
115
  // If the resolved IP is NOT allowed (e.g., a private IP), destroy the connection.
116
116
  return client?.destroy(new Error(`DNS lookup ${ipToCheck} is not allowed.`));
117
117
  }
@@ -119,6 +119,7 @@ function index (url, isValidDomainOptions) {
119
119
  return client;
120
120
  };
121
121
  return finalAgent;
122
- }
122
+ };
123
+ module.exports = ssrfAgentGuard;
123
124
 
124
- exports.default = index;
125
+ exports.default = ssrfAgentGuard;
@@ -0,0 +1,14 @@
1
+ import { Agent as HttpAgent } from 'http';
2
+ import { Agent as HttpsAgent } from 'https';
3
+ import { IsValidDomainOptions } from './lib/types';
4
+ type CustomAgent = HttpAgent | HttpsAgent;
5
+ /**
6
+ * Patches an http.Agent or https.Agent to enforce an HOST/IP check
7
+ * before and after a DNS lookup.
8
+ *
9
+ * @param url The URL or another input to determine the agent type.
10
+ * @param isValidDomainOptions Options for validating domain names.
11
+ * @returns The patched CustomAgent instance.
12
+ */
13
+ declare const ssrfAgentGuard: (url: string, isValidDomainOptions?: IsValidDomainOptions) => CustomAgent;
14
+ export default ssrfAgentGuard;
package/dist/index.esm.js CHANGED
@@ -45,7 +45,7 @@ function isSafeHost(hostname, isValidDomainOptions) {
45
45
  // Case 2: Domain name
46
46
  return isValidDomain(hostname, {
47
47
  allowUnicode: false,
48
- subdomain: false,
48
+ subdomain: true,
49
49
  ...isValidDomainOptions,
50
50
  });
51
51
  }
@@ -76,7 +76,7 @@ const CREATE_CONNECTION = Symbol('createConnection');
76
76
  * @param isValidDomainOptions Options for validating domain names.
77
77
  * @returns The patched CustomAgent instance.
78
78
  */
79
- function index (url, isValidDomainOptions) {
79
+ const ssrfAgentGuard = function (url, isValidDomainOptions) {
80
80
  const finalAgent = getAgent(url);
81
81
  // Prevent patching the agent multiple times
82
82
  if (finalAgent[CREATE_CONNECTION]) {
@@ -107,7 +107,7 @@ function index (url, isValidDomainOptions) {
107
107
  }
108
108
  // Ensure resolvedAddress is a string for the check (it's typically a string for simple lookups)
109
109
  const ipToCheck = Array.isArray(resolvedAddress) ? resolvedAddress[0] : resolvedAddress;
110
- if (!isSafeIp(ipToCheck)) {
110
+ if (!isSafeHost(ipToCheck)) {
111
111
  // If the resolved IP is NOT allowed (e.g., a private IP), destroy the connection.
112
112
  return client?.destroy(new Error(`DNS lookup ${ipToCheck} is not allowed.`));
113
113
  }
@@ -115,6 +115,7 @@ function index (url, isValidDomainOptions) {
115
115
  return client;
116
116
  };
117
117
  return finalAgent;
118
- }
118
+ };
119
+ module.exports = ssrfAgentGuard;
119
120
 
120
- export { index as default };
121
+ export { ssrfAgentGuard as default };
@@ -0,0 +1,27 @@
1
+ export interface Options {
2
+ protocal?: string;
3
+ metadataHosts?: string[];
4
+ mode?: 'block' | 'report' | 'allow';
5
+ policy?: PolicyOptions;
6
+ blockCloudMetadata?: boolean;
7
+ detectDnsRebinding?: boolean;
8
+ logger?: (level: 'info' | 'warn' | 'error', msg: string, meta?: any) => void;
9
+ }
10
+ export interface PolicyOptions {
11
+ allowDomains?: string[];
12
+ denyDomains?: string[];
13
+ denyTLD?: string[];
14
+ }
15
+ export interface BlockEvent {
16
+ url: string;
17
+ reason: string;
18
+ ip?: string;
19
+ timestamp: number;
20
+ }
21
+ export interface IsValidDomainOptions {
22
+ subdomain?: boolean;
23
+ wildcard?: boolean;
24
+ allowUnicode?: boolean;
25
+ topLevel?: boolean;
26
+ }
27
+ export declare const CLOUD_METADATA_HOSTS: string[];
@@ -0,0 +1,9 @@
1
+ import { IsValidDomainOptions } from './types';
2
+ /**
3
+ * Validates whether a domain is syntactically valid.
4
+ */
5
+ export declare function isSafeIp(hostname: string): boolean;
6
+ /**
7
+ * High-level validation for hostnames (domains + public IPs).
8
+ */
9
+ export declare function isSafeHost(hostname: string, isValidDomainOptions?: IsValidDomainOptions): boolean;
package/index.ts CHANGED
@@ -38,7 +38,7 @@ const CREATE_CONNECTION = Symbol('createConnection');
38
38
  * @param isValidDomainOptions Options for validating domain names.
39
39
  * @returns The patched CustomAgent instance.
40
40
  */
41
- export default function (url: string, isValidDomainOptions?: IsValidDomainOptions): CustomAgent {
41
+ const ssrfAgentGuard = function (url: string, isValidDomainOptions?: IsValidDomainOptions): CustomAgent {
42
42
  const finalAgent = getAgent(url);
43
43
 
44
44
  // Prevent patching the agent multiple times
@@ -79,7 +79,7 @@ export default function (url: string, isValidDomainOptions?: IsValidDomainOption
79
79
  // Ensure resolvedAddress is a string for the check (it's typically a string for simple lookups)
80
80
  const ipToCheck = Array.isArray(resolvedAddress) ? resolvedAddress[0] : resolvedAddress;
81
81
 
82
- if (!isSafeIp(ipToCheck)) {
82
+ if (!isSafeHost(ipToCheck)) {
83
83
  // If the resolved IP is NOT allowed (e.g., a private IP), destroy the connection.
84
84
  return client?.destroy(new Error(`DNS lookup ${ipToCheck} is not allowed.`));
85
85
  }
@@ -90,3 +90,6 @@ export default function (url: string, isValidDomainOptions?: IsValidDomainOption
90
90
 
91
91
  return finalAgent;
92
92
  }
93
+
94
+ export default ssrfAgentGuard;
95
+ module.exports = ssrfAgentGuard;
package/lib/utils.ts CHANGED
@@ -40,7 +40,7 @@ export function isSafeHost(hostname: string, isValidDomainOptions?: IsValidDomai
40
40
  // Case 2: Domain name
41
41
  return isValidDomain(hostname, {
42
42
  allowUnicode: false,
43
- subdomain: false,
43
+ subdomain: true,
44
44
  ...isValidDomainOptions,
45
45
  });
46
46
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ssrf-agent-guard",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "A TypeScript SSRF protection library for Node.js (express/axios) with advanced policies, DNS rebinding detection and cloud metadata protection.",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",
package/tsconfig.json CHANGED
@@ -3,6 +3,8 @@
3
3
  "target": "ES2020",
4
4
  "module": "ESNext",
5
5
  "declaration": true,
6
+ "emitDeclarationOnly": false,
7
+ "declarationDir": "./dist",
6
8
  "outDir": "dist",
7
9
  "strict": true,
8
10
  "esModuleInterop": true,
@@ -10,7 +12,7 @@
10
12
  "skipLibCheck": true
11
13
  },
12
14
  "include": [
13
- "lib/**/*",
15
+ "lib/**/*",
14
16
  "rollup.config.mjs"
15
17
  ]
16
18
  }