From minified
to magnified
🔍
What is a source map?
Source map
- maps the minified code to the original
- created during a build process
Visualization
Format
{
"version": 3,
"sources": [
"/Users/martin.nuc/programming/temp/sourcemaps/src/second.ts",
"/Users/martin.nuc/programming/temp/sourcemaps/src/index.ts"
],
"sourcesContent": [
"export const result = 1 + 5;",
"import { result } from './second';\n\nconsole.log('ahoj', result)\n\nsetName({}, 'Martin');\nsetName({}, 'Lukas');\n\nfunction setName(person, name) {\n let magicNumber = 12345;\n person.number = magicNumber;\n magicNumber++\n person.name = name + magicNumber;\n}"
],
"names": [],
"mappings": "AAAO,IAAM,SAAS;ACOtB,SAAS,EAAQ,CAAM,EAAE,CAAI;IAC3B,IAAI,IAAc;IAClB,EAAO,MAAM,GAAG,GAChB,KACA,EAAO,IAAI,GAAG,IAAO;AACvB;AAVA,QAAQ,GAAG,CAAC,iBAEZ,EAAQ,CAAC,GAAG,WACZ,EAAQ,CAAC,GAAG"
}
Mappings
- ; = separates lines
- , = separates segments
- segments are 1, 4 or 5 size long
- build on top of the previous segment
- encodes the file, line and column using Base64 VLQ
AAAO,IAAM,SAAS;ACOtB,SAAS,EAAQ,CAAM,EAAE,CAAI;IAC3B,IAAI,IAAc;IAClB,EAAO,MAAM,GAAG,GAChB,KACA,EAAO,IAAI,GAAG,IAAO;AACvB;AAVA
Size of source map
- mappings is a big string
- v1 ~10x the generated code
- v2 ~5x the generated code
- v3 ~2.5x the generated code
How to use source maps?
1. comment
... generated file ...
//# sourceMappingURL=/path/to/file.js.map
2. HTTP header
SourceMap: <url>
Configure build tool
- for webpack SourceMapDevToolPlugin
new webpack.SourceMapDevToolPlugin({
// append: '\n//# sourceMappingURL=https://example.com/file.js',
publicPath: 'https://example.com/',
filename: '[file].map',
});
Source maps are language agnostic



Be careful
‼️
‼️
Never make source maps public!
{
"version": 3,
"sources": [
"/Users/martin.nuc/programming/temp/sourcemaps/src/second.ts",
"/Users/martin.nuc/programming/temp/sourcemaps/src/index.ts"
],
"sourcesContent": [
"export const result = 1 + 5;",
"import { result } from './second';\n\nconsole.log('ahoj', result)\n\nsetName({}, 'Martin');\nsetName({}, 'Lukas');\n\nfunction setName(person, name) {\n let magicNumber = 12345;\n person.number = magicNumber;\n magicNumber++\n person.name = name + magicNumber;\n}"
],
"names": [],
"mappings": "AAAO,IAAM,SAAS;ACOtB,SAAS,EAAQ,CAAM,EAAE,CAAI;IAC3B,IAAI,IAAc;IAClB,EAAO,MAAM,GAAG,GAChB,KACA,EAAO,IAAI,GAAG,IAAO;AACvB;AAVA,QAAQ,GAAG,CAAC,iBAEZ,EAAQ,CAAC,GAAG,WACZ,EAAQ,CAAC,GAAG"
}
‼️
Our approach: VPN
- hide sourcemaps in S3 bucket accessible via VPN
Browser
S3 with sourcemaps
HTML, JS, CSS
Accessible only via VPN
The end of our story
- Impersonation
- Source maps via VPN
References
From minified to magnified
By Martin Nuc
From minified to magnified
- 120