@arcadialdev/arcality 2.4.25 → 2.4.26

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.
@@ -1,265 +1,265 @@
1
- /* eslint-disable no-console */
2
- import { Page, expect } from '@playwright/test';
3
-
4
- export type Severity = 'Critical' | 'High' | 'Medium' | 'Low' | 'Info';
5
-
6
- export type SecurityFindingType = 'confirmed_vulnerability' | 'security_misconfiguration' | 'potential_issue' | 'informational';
7
- export type Confidence = 'High' | 'Medium' | 'Low';
8
- export type Exploitability = 'confirmed' | 'likely' | 'unknown' | 'not_confirmed';
9
-
10
- export interface SecurityFinding {
11
- type: SecurityFindingType;
12
- category: string;
13
- subcategory?: string;
14
- severity: Severity;
15
- confidence: Confidence;
16
- exploitability: Exploitability;
17
- status: 'detected';
18
- description: string;
19
- impact?: string;
20
- evidence: {
21
- [key: string]: any;
22
- };
23
- reproductionSteps?: string[];
24
- remediation: string;
25
- classification?: {
26
- owaspTop10?: string;
27
- cwe?: string;
28
- };
29
- }
30
-
31
- /**
32
- * Attempts to inject a simple XSS payload into a specified element and checks for an alert.
33
- * @param page - The Playwright Page object.
34
- * @param selector - The selector for the input field to test.
35
- * @returns A vulnerability object if successful, null otherwise.
36
- */
37
- export async function test_xss_injection(
38
- page: Page,
39
- selector: string,
40
- ): Promise<SecurityFinding | null> {
41
- const payload = `<script>alert('XSS-ARCALITY-TEST')</script>`;
42
- console.log(`[QA-SEC] Testing XSS on selector: ${selector}`);
43
-
44
- let alertTriggered = false;
45
- page.once('dialog', async (dialog) => {
46
- if (dialog.message().includes('XSS-ARCALITY-TEST')) {
47
- alertTriggered = true;
48
- }
49
- await dialog.dismiss();
50
- });
51
-
52
- await page.fill(selector, payload);
53
- // Submit the form or trigger the action that would process the input
54
- // This part is crucial and might need to be adapted based on the application's behavior
55
- await page.press(selector, 'Enter');
56
-
57
- // Wait a moment for any potential script execution
58
- await page.waitForTimeout(1000);
59
-
60
- if (alertTriggered) {
61
- console.log(`[QA-SEC] XSS Vulnerability DETECTED at ${selector}`);
62
- return {
63
- type: 'confirmed_vulnerability',
64
- category: 'Injection',
65
- subcategory: 'Reflected XSS',
66
- severity: 'High',
67
- confidence: 'High',
68
- exploitability: 'confirmed',
69
- status: 'detected',
70
- description: `A reflected Cross-Site Scripting (XSS) vulnerability was detected in the element '${selector}'. The application executed a script injected into this input field.`,
71
- impact: 'Allows execution of arbitrary JavaScript in the context of the user session, potentially leading to session hijacking, credential theft, or unauthorized actions.',
72
- evidence: {
73
- payload,
74
- url: page.url(),
75
- selector,
76
- },
77
- reproductionSteps: [
78
- `Navigate to the page containing '${selector}'.`,
79
- `Inject the payload: ${payload}`,
80
- 'Trigger the form submission or blur event.',
81
- 'Observe the script execution (alert dialog).'
82
- ],
83
- remediation: 'Sanitize all user-supplied input on the server-side before rendering it back to the page. Use libraries like DOMPurify on the client-side as an additional layer of defense.',
84
- classification: {
85
- owaspTop10: 'A03:2021 Injection',
86
- cwe: 'CWE-79'
87
- }
88
- };
89
- }
90
-
91
- console.log(`[QA-SEC] No XSS detected for selector: ${selector}`);
92
- return null;
93
- }
94
-
95
- /**
96
- * Checks if a given URL, assumed to be protected, can be accessed without authentication.
97
- * @param page - The Playwright Page object.
98
- * @param url - The protected URL to test.
99
- * @param redirectUrl - The URL the app should redirect to if unauthorized.
100
- * @returns A vulnerability object if bypass is successful, null otherwise.
101
- */
102
- export async function test_auth_bypass(
103
- page: Page,
104
- url: string,
105
- redirectUrl: string | RegExp,
106
- ): Promise<SecurityFinding | null> {
107
- console.log(`[QA-SEC] Testing Auth Bypass on URL: ${url}`);
108
- const response = await page.goto(url, { waitUntil: 'domcontentloaded' });
109
-
110
- // If the page loads the protected content (doesn't redirect or redirects to a different page)
111
- if (response?.ok() && !page.url().match(redirectUrl)) {
112
- console.log(`[QA-SEC] Auth Bypass DETECTED for URL: ${url}`);
113
- return {
114
- type: 'confirmed_vulnerability',
115
- category: 'Broken Access Control',
116
- subcategory: 'Authentication Bypass',
117
- severity: 'Critical',
118
- confidence: 'High',
119
- exploitability: 'confirmed',
120
- status: 'detected',
121
- description: `Unauthorized access to the protected route '${url}' was successful. The application failed to enforce authentication, allowing a direct bypass to sensitive content.`,
122
- impact: 'An unauthenticated attacker can access protected resources, potentially reading or modifying sensitive user data.',
123
- evidence: {
124
- accessedUrl: url,
125
- finalUrl: page.url(),
126
- },
127
- reproductionSteps: [
128
- 'Ensure no active session (cleared cookies/storage).',
129
- `Navigate directly to: ${url}`,
130
- 'Observe that the protected page loads without redirection.'
131
- ],
132
- remediation: 'Implement server-side middleware to verify user authentication and authorization status before serving any protected routes.',
133
- classification: {
134
- owaspTop10: 'A01:2021 Broken Access Control',
135
- cwe: 'CWE-285'
136
- }
137
- };
138
- }
139
-
140
- console.log(`[QA-SEC] No Auth Bypass detected for URL: ${url}`);
141
- return null;
142
- }
143
-
144
- /**
145
- * Audits the HTTP security headers of the current page.
146
- * @param page - The Playwright Page object.
147
- * @returns An array of vulnerability objects for missing headers.
148
- */
149
- export async function audit_http_headers(page: Page): Promise<SecurityFinding[]> {
150
- console.log(`[QA-SEC] Auditing HTTP Headers for: ${page.url()}`);
151
- const response = await page.reload({ waitUntil: 'domcontentloaded' });
152
- const headers = response?.headers();
153
- const vulnerabilities: SecurityFinding[] = [];
154
-
155
- const securityHeaders = {
156
- 'Content-Security-Policy': {
157
- severity: 'Medium',
158
- remediation: 'Implement a strict Content-Security-Policy (CSP) to mitigate XSS and other injection attacks. Start with a restrictive policy and gradually allow trusted sources.',
159
- impact: 'If an injection issue exists elsewhere in the application, the lack of CSP may increase exploitability and impact.',
160
- cwe: 'CWE-16'
161
- },
162
- 'Strict-Transport-Security': {
163
- severity: 'Medium',
164
- remediation: 'Implement HTTP Strict Transport Security (HSTS) to force browsers to communicate over HTTPS, preventing downgrade attacks.',
165
- impact: 'Man-in-the-middle attacks could downgrade the connection to HTTP, allowing traffic interception.',
166
- cwe: 'CWE-319'
167
- },
168
- 'X-Content-Type-Options': {
169
- severity: 'Low',
170
- remediation: 'Set `X-Content-Type-Options: nosniff` to prevent browsers from MIME-sniffing a response away from the declared content-type.',
171
- impact: 'Browsers may interpret non-executable MIME types as executable, leading to potential XSS.',
172
- cwe: 'CWE-430'
173
- },
174
- 'X-Frame-Options': {
175
- severity: 'Medium',
176
- remediation: 'Set `X-Frame-Options: SAMEORIGIN` or `DENY` to protect against clickjacking attacks by preventing the page from being loaded in an iframe on other domains.',
177
- impact: 'Attackers could trick users into clicking visually hidden elements, causing unintended actions (Clickjacking).',
178
- cwe: 'CWE-1021'
179
- }
180
- };
181
-
182
- for (const [header, info] of Object.entries(securityHeaders)) {
183
- if (!headers || !Object.keys(headers).find(h => h.toLowerCase() === header.toLowerCase())) {
184
- vulnerabilities.push({
185
- type: 'security_misconfiguration',
186
- category: 'Missing Security Header',
187
- subcategory: header,
188
- severity: info.severity as Severity,
189
- confidence: 'High',
190
- exploitability: 'not_confirmed',
191
- status: 'detected',
192
- description: `The '${header}' HTTP header is missing. This header is crucial for defending against various web attacks.`,
193
- impact: info.impact,
194
- evidence: {
195
- url: page.url(),
196
- missingHeader: header
197
- },
198
- reproductionSteps: [
199
- `Navigate to ${page.url()}`,
200
- `Inspect the response headers.`,
201
- `Verify that ${header} is absent.`
202
- ],
203
- remediation: info.remediation,
204
- classification: {
205
- owaspTop10: 'A05:2021 Security Misconfiguration',
206
- cwe: info.cwe
207
- }
208
- });
209
- }
210
- }
211
-
212
- console.log(`[QA-SEC] Found ${vulnerabilities.length} missing security headers.`);
213
- return vulnerabilities;
214
- }
215
-
216
- /**
217
- * Scans localStorage and sessionStorage for potentially sensitive data.
218
- * @param page - The Playwright Page object.
219
- * @returns An array of vulnerability objects for any sensitive data found.
220
- */
221
- export async function scan_sensitive_data_exposure(page: Page): Promise<SecurityFinding[]> {
222
- console.log(`[QA-SEC] Scanning localStorage and sessionStorage for sensitive data.`);
223
- const vulnerabilities: SecurityFinding[] = [];
224
- const sensitiveKeywords = ['token', 'password', 'secret', 'key', 'jwt', 'auth'];
225
-
226
- const storages = {
227
- localStorage: await page.evaluate(() => Object.entries(window.localStorage)),
228
- sessionStorage: await page.evaluate(() => Object.entries(window.sessionStorage)),
229
- };
230
-
231
- for (const [storageType, items] of Object.entries(storages)) {
232
- for (const [key, value] of items) {
233
- if (sensitiveKeywords.some(keyword => key.toLowerCase().includes(keyword))) {
234
- vulnerabilities.push({
235
- type: 'potential_issue',
236
- category: 'Sensitive Data Exposure',
237
- subcategory: 'Browser Storage',
238
- severity: 'Medium',
239
- confidence: 'Medium',
240
- exploitability: 'unknown',
241
- status: 'detected',
242
- description: `Potentially sensitive data was found in ${storageType}. Storing sensitive information like tokens or keys in browser storage is insecure.`,
243
- impact: 'If an attacker discovers an XSS vulnerability, they can read localStorage/sessionStorage and exfiltrate secrets.',
244
- evidence: {
245
- storage: storageType,
246
- key: key,
247
- valuePreview: value ? `${value.substring(0, 10)}...` : '(empty)',
248
- },
249
- reproductionSteps: [
250
- `Open Developer Tools on ${page.url()}`,
251
- `Check ${storageType} for the key '${key}'.`
252
- ],
253
- remediation: 'Avoid storing sensitive data in browser storage. Use secure, HttpOnly cookies for session tokens. If you must store data, encrypt it first.',
254
- classification: {
255
- owaspTop10: 'A04:2021 Insecure Design',
256
- cwe: 'CWE-312'
257
- }
258
- });
259
- }
260
- }
261
- }
262
-
263
- console.log(`[QA-SEC] Found ${vulnerabilities.length} instances of sensitive data in browser storage.`);
264
- return vulnerabilities;
265
- }
1
+ /* eslint-disable no-console */
2
+ import { Page, expect } from '@playwright/test';
3
+
4
+ export type Severity = 'Critical' | 'High' | 'Medium' | 'Low' | 'Info';
5
+
6
+ export type SecurityFindingType = 'confirmed_vulnerability' | 'security_misconfiguration' | 'potential_issue' | 'informational';
7
+ export type Confidence = 'High' | 'Medium' | 'Low';
8
+ export type Exploitability = 'confirmed' | 'likely' | 'unknown' | 'not_confirmed';
9
+
10
+ export interface SecurityFinding {
11
+ type: SecurityFindingType;
12
+ category: string;
13
+ subcategory?: string;
14
+ severity: Severity;
15
+ confidence: Confidence;
16
+ exploitability: Exploitability;
17
+ status: 'detected';
18
+ description: string;
19
+ impact?: string;
20
+ evidence: {
21
+ [key: string]: any;
22
+ };
23
+ reproductionSteps?: string[];
24
+ remediation: string;
25
+ classification?: {
26
+ owaspTop10?: string;
27
+ cwe?: string;
28
+ };
29
+ }
30
+
31
+ /**
32
+ * Attempts to inject a simple XSS payload into a specified element and checks for an alert.
33
+ * @param page - The Playwright Page object.
34
+ * @param selector - The selector for the input field to test.
35
+ * @returns A vulnerability object if successful, null otherwise.
36
+ */
37
+ export async function test_xss_injection(
38
+ page: Page,
39
+ selector: string,
40
+ ): Promise<SecurityFinding | null> {
41
+ const payload = `<script>alert('XSS-ARCALITY-TEST')</script>`;
42
+ console.log(`[QA-SEC] Testing XSS on selector: ${selector}`);
43
+
44
+ let alertTriggered = false;
45
+ page.once('dialog', async (dialog) => {
46
+ if (dialog.message().includes('XSS-ARCALITY-TEST')) {
47
+ alertTriggered = true;
48
+ }
49
+ await dialog.dismiss();
50
+ });
51
+
52
+ await page.fill(selector, payload);
53
+ // Submit the form or trigger the action that would process the input
54
+ // This part is crucial and might need to be adapted based on the application's behavior
55
+ await page.press(selector, 'Enter');
56
+
57
+ // Wait a moment for any potential script execution
58
+ await page.waitForTimeout(1000);
59
+
60
+ if (alertTriggered) {
61
+ console.log(`[QA-SEC] XSS Vulnerability DETECTED at ${selector}`);
62
+ return {
63
+ type: 'confirmed_vulnerability',
64
+ category: 'Injection',
65
+ subcategory: 'Reflected XSS',
66
+ severity: 'High',
67
+ confidence: 'High',
68
+ exploitability: 'confirmed',
69
+ status: 'detected',
70
+ description: `A reflected Cross-Site Scripting (XSS) vulnerability was detected in the element '${selector}'. The application executed a script injected into this input field.`,
71
+ impact: 'Allows execution of arbitrary JavaScript in the context of the user session, potentially leading to session hijacking, credential theft, or unauthorized actions.',
72
+ evidence: {
73
+ payload,
74
+ url: page.url(),
75
+ selector,
76
+ },
77
+ reproductionSteps: [
78
+ `Navigate to the page containing '${selector}'.`,
79
+ `Inject the payload: ${payload}`,
80
+ 'Trigger the form submission or blur event.',
81
+ 'Observe the script execution (alert dialog).'
82
+ ],
83
+ remediation: 'Sanitize all user-supplied input on the server-side before rendering it back to the page. Use libraries like DOMPurify on the client-side as an additional layer of defense.',
84
+ classification: {
85
+ owaspTop10: 'A03:2021 Injection',
86
+ cwe: 'CWE-79'
87
+ }
88
+ };
89
+ }
90
+
91
+ console.log(`[QA-SEC] No XSS detected for selector: ${selector}`);
92
+ return null;
93
+ }
94
+
95
+ /**
96
+ * Checks if a given URL, assumed to be protected, can be accessed without authentication.
97
+ * @param page - The Playwright Page object.
98
+ * @param url - The protected URL to test.
99
+ * @param redirectUrl - The URL the app should redirect to if unauthorized.
100
+ * @returns A vulnerability object if bypass is successful, null otherwise.
101
+ */
102
+ export async function test_auth_bypass(
103
+ page: Page,
104
+ url: string,
105
+ redirectUrl: string | RegExp,
106
+ ): Promise<SecurityFinding | null> {
107
+ console.log(`[QA-SEC] Testing Auth Bypass on URL: ${url}`);
108
+ const response = await page.goto(url, { waitUntil: 'domcontentloaded' });
109
+
110
+ // If the page loads the protected content (doesn't redirect or redirects to a different page)
111
+ if (response?.ok() && !page.url().match(redirectUrl)) {
112
+ console.log(`[QA-SEC] Auth Bypass DETECTED for URL: ${url}`);
113
+ return {
114
+ type: 'confirmed_vulnerability',
115
+ category: 'Broken Access Control',
116
+ subcategory: 'Authentication Bypass',
117
+ severity: 'Critical',
118
+ confidence: 'High',
119
+ exploitability: 'confirmed',
120
+ status: 'detected',
121
+ description: `Unauthorized access to the protected route '${url}' was successful. The application failed to enforce authentication, allowing a direct bypass to sensitive content.`,
122
+ impact: 'An unauthenticated attacker can access protected resources, potentially reading or modifying sensitive user data.',
123
+ evidence: {
124
+ accessedUrl: url,
125
+ finalUrl: page.url(),
126
+ },
127
+ reproductionSteps: [
128
+ 'Ensure no active session (cleared cookies/storage).',
129
+ `Navigate directly to: ${url}`,
130
+ 'Observe that the protected page loads without redirection.'
131
+ ],
132
+ remediation: 'Implement server-side middleware to verify user authentication and authorization status before serving any protected routes.',
133
+ classification: {
134
+ owaspTop10: 'A01:2021 Broken Access Control',
135
+ cwe: 'CWE-285'
136
+ }
137
+ };
138
+ }
139
+
140
+ console.log(`[QA-SEC] No Auth Bypass detected for URL: ${url}`);
141
+ return null;
142
+ }
143
+
144
+ /**
145
+ * Audits the HTTP security headers of the current page.
146
+ * @param page - The Playwright Page object.
147
+ * @returns An array of vulnerability objects for missing headers.
148
+ */
149
+ export async function audit_http_headers(page: Page): Promise<SecurityFinding[]> {
150
+ console.log(`[QA-SEC] Auditing HTTP Headers for: ${page.url()}`);
151
+ const response = await page.reload({ waitUntil: 'domcontentloaded' });
152
+ const headers = response?.headers();
153
+ const vulnerabilities: SecurityFinding[] = [];
154
+
155
+ const securityHeaders = {
156
+ 'Content-Security-Policy': {
157
+ severity: 'Medium',
158
+ remediation: 'Implement a strict Content-Security-Policy (CSP) to mitigate XSS and other injection attacks. Start with a restrictive policy and gradually allow trusted sources.',
159
+ impact: 'If an injection issue exists elsewhere in the application, the lack of CSP may increase exploitability and impact.',
160
+ cwe: 'CWE-16'
161
+ },
162
+ 'Strict-Transport-Security': {
163
+ severity: 'Medium',
164
+ remediation: 'Implement HTTP Strict Transport Security (HSTS) to force browsers to communicate over HTTPS, preventing downgrade attacks.',
165
+ impact: 'Man-in-the-middle attacks could downgrade the connection to HTTP, allowing traffic interception.',
166
+ cwe: 'CWE-319'
167
+ },
168
+ 'X-Content-Type-Options': {
169
+ severity: 'Low',
170
+ remediation: 'Set `X-Content-Type-Options: nosniff` to prevent browsers from MIME-sniffing a response away from the declared content-type.',
171
+ impact: 'Browsers may interpret non-executable MIME types as executable, leading to potential XSS.',
172
+ cwe: 'CWE-430'
173
+ },
174
+ 'X-Frame-Options': {
175
+ severity: 'Medium',
176
+ remediation: 'Set `X-Frame-Options: SAMEORIGIN` or `DENY` to protect against clickjacking attacks by preventing the page from being loaded in an iframe on other domains.',
177
+ impact: 'Attackers could trick users into clicking visually hidden elements, causing unintended actions (Clickjacking).',
178
+ cwe: 'CWE-1021'
179
+ }
180
+ };
181
+
182
+ for (const [header, info] of Object.entries(securityHeaders)) {
183
+ if (!headers || !Object.keys(headers).find(h => h.toLowerCase() === header.toLowerCase())) {
184
+ vulnerabilities.push({
185
+ type: 'security_misconfiguration',
186
+ category: 'Missing Security Header',
187
+ subcategory: header,
188
+ severity: info.severity as Severity,
189
+ confidence: 'High',
190
+ exploitability: 'not_confirmed',
191
+ status: 'detected',
192
+ description: `The '${header}' HTTP header is missing. This header is crucial for defending against various web attacks.`,
193
+ impact: info.impact,
194
+ evidence: {
195
+ url: page.url(),
196
+ missingHeader: header
197
+ },
198
+ reproductionSteps: [
199
+ `Navigate to ${page.url()}`,
200
+ `Inspect the response headers.`,
201
+ `Verify that ${header} is absent.`
202
+ ],
203
+ remediation: info.remediation,
204
+ classification: {
205
+ owaspTop10: 'A05:2021 Security Misconfiguration',
206
+ cwe: info.cwe
207
+ }
208
+ });
209
+ }
210
+ }
211
+
212
+ console.log(`[QA-SEC] Found ${vulnerabilities.length} missing security headers.`);
213
+ return vulnerabilities;
214
+ }
215
+
216
+ /**
217
+ * Scans localStorage and sessionStorage for potentially sensitive data.
218
+ * @param page - The Playwright Page object.
219
+ * @returns An array of vulnerability objects for any sensitive data found.
220
+ */
221
+ export async function scan_sensitive_data_exposure(page: Page): Promise<SecurityFinding[]> {
222
+ console.log(`[QA-SEC] Scanning localStorage and sessionStorage for sensitive data.`);
223
+ const vulnerabilities: SecurityFinding[] = [];
224
+ const sensitiveKeywords = ['token', 'password', 'secret', 'key', 'jwt', 'auth'];
225
+
226
+ const storages = {
227
+ localStorage: await page.evaluate(() => Object.entries(window.localStorage)),
228
+ sessionStorage: await page.evaluate(() => Object.entries(window.sessionStorage)),
229
+ };
230
+
231
+ for (const [storageType, items] of Object.entries(storages)) {
232
+ for (const [key, value] of items) {
233
+ if (sensitiveKeywords.some(keyword => key.toLowerCase().includes(keyword))) {
234
+ vulnerabilities.push({
235
+ type: 'potential_issue',
236
+ category: 'Sensitive Data Exposure',
237
+ subcategory: 'Browser Storage',
238
+ severity: 'Medium',
239
+ confidence: 'Medium',
240
+ exploitability: 'unknown',
241
+ status: 'detected',
242
+ description: `Potentially sensitive data was found in ${storageType}. Storing sensitive information like tokens or keys in browser storage is insecure.`,
243
+ impact: 'If an attacker discovers an XSS vulnerability, they can read localStorage/sessionStorage and exfiltrate secrets.',
244
+ evidence: {
245
+ storage: storageType,
246
+ key: key,
247
+ valuePreview: value ? `${value.substring(0, 10)}...` : '(empty)',
248
+ },
249
+ reproductionSteps: [
250
+ `Open Developer Tools on ${page.url()}`,
251
+ `Check ${storageType} for the key '${key}'.`
252
+ ],
253
+ remediation: 'Avoid storing sensitive data in browser storage. Use secure, HttpOnly cookies for session tokens. If you must store data, encrypt it first.',
254
+ classification: {
255
+ owaspTop10: 'A04:2021 Insecure Design',
256
+ cwe: 'CWE-312'
257
+ }
258
+ });
259
+ }
260
+ }
261
+ }
262
+
263
+ console.log(`[QA-SEC] Found ${vulnerabilities.length} instances of sensitive data in browser storage.`);
264
+ return vulnerabilities;
265
+ }