@preship/secrets 1.0.0 → 1.0.2
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/dist/index.js +70 -10
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -417,14 +417,17 @@ var genericRules = [
|
|
|
417
417
|
keywords: [],
|
|
418
418
|
// No keyword prefilter; this rule is opt-in via entropy threshold
|
|
419
419
|
pattern: /[A-Za-z0-9+/]{40,}={0,2}/,
|
|
420
|
-
entropyThreshold:
|
|
420
|
+
entropyThreshold: 5.5,
|
|
421
|
+
// Raised from 4.5 — base64 is naturally ~5.0-5.5 entropy, so only truly random strings pass
|
|
421
422
|
allowPatterns: [
|
|
422
423
|
/^[A-Z]+$/,
|
|
423
424
|
// All uppercase (likely a constant name)
|
|
424
425
|
/^[a-z]+$/,
|
|
425
426
|
// All lowercase (likely a word)
|
|
426
|
-
/[A-Za-z]{40,}
|
|
427
|
+
/[A-Za-z]{40,}/,
|
|
427
428
|
// Long alphabetic-only strings are typically not secrets
|
|
429
|
+
/={2}$/
|
|
430
|
+
// Strings ending with == are typically short padded data (hashes, encoded values), not secrets
|
|
428
431
|
]
|
|
429
432
|
},
|
|
430
433
|
{
|
|
@@ -434,12 +437,17 @@ var genericRules = [
|
|
|
434
437
|
keywords: [],
|
|
435
438
|
// No keyword prefilter; this rule is opt-in via entropy threshold
|
|
436
439
|
pattern: /[0-9a-fA-F]{40,}/,
|
|
437
|
-
entropyThreshold: 3,
|
|
440
|
+
entropyThreshold: 3.5,
|
|
441
|
+
// Raised from 3.0 — git commit hashes and content hashes typically hit 3.0-3.5
|
|
438
442
|
allowPatterns: [
|
|
439
443
|
/^0{10,}$/,
|
|
440
444
|
// All zeros (placeholder/null hash)
|
|
441
|
-
/^[fF]{10,}
|
|
445
|
+
/^[fF]{10,}$/,
|
|
442
446
|
// All f's (mask value)
|
|
447
|
+
/^[0-9a-f]{40}$/,
|
|
448
|
+
// Exactly 40 hex chars = git SHA1 commit hash (not a secret)
|
|
449
|
+
/^[0-9a-f]{64}$/
|
|
450
|
+
// Exactly 64 hex chars = SHA256 hash (integrity check, not a secret)
|
|
443
451
|
]
|
|
444
452
|
}
|
|
445
453
|
];
|
|
@@ -483,6 +491,7 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
483
491
|
".output"
|
|
484
492
|
]);
|
|
485
493
|
var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
494
|
+
// Images
|
|
486
495
|
".png",
|
|
487
496
|
".jpg",
|
|
488
497
|
".jpeg",
|
|
@@ -492,11 +501,13 @@ var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
492
501
|
".webp",
|
|
493
502
|
".bmp",
|
|
494
503
|
".tiff",
|
|
504
|
+
// Fonts
|
|
495
505
|
".woff",
|
|
496
506
|
".woff2",
|
|
497
507
|
".ttf",
|
|
498
508
|
".eot",
|
|
499
509
|
".otf",
|
|
510
|
+
// Documents & archives
|
|
500
511
|
".pdf",
|
|
501
512
|
".zip",
|
|
502
513
|
".tar",
|
|
@@ -507,6 +518,7 @@ var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
507
518
|
".rar",
|
|
508
519
|
".jar",
|
|
509
520
|
".war",
|
|
521
|
+
// Binaries
|
|
510
522
|
".exe",
|
|
511
523
|
".dll",
|
|
512
524
|
".so",
|
|
@@ -518,18 +530,33 @@ var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
518
530
|
".pyc",
|
|
519
531
|
".pyo",
|
|
520
532
|
".wasm",
|
|
533
|
+
// Media
|
|
521
534
|
".mp3",
|
|
522
535
|
".mp4",
|
|
523
536
|
".avi",
|
|
524
537
|
".mov",
|
|
525
538
|
".mkv",
|
|
526
539
|
".flac",
|
|
527
|
-
".wav"
|
|
540
|
+
".wav",
|
|
541
|
+
// Source maps (contain base64 noise, not real secrets)
|
|
542
|
+
".map",
|
|
543
|
+
// Data files
|
|
544
|
+
".sqlite",
|
|
545
|
+
".db"
|
|
528
546
|
]);
|
|
529
|
-
var
|
|
547
|
+
var SKIP_FILENAMES = /* @__PURE__ */ new Set([
|
|
530
548
|
"package-lock.json",
|
|
531
549
|
"yarn.lock",
|
|
532
|
-
"pnpm-lock.yaml"
|
|
550
|
+
"pnpm-lock.yaml",
|
|
551
|
+
"npm-shrinkwrap.json",
|
|
552
|
+
"composer.lock",
|
|
553
|
+
"Gemfile.lock",
|
|
554
|
+
"Cargo.lock",
|
|
555
|
+
"poetry.lock",
|
|
556
|
+
"Pipfile.lock",
|
|
557
|
+
// PreShip internal files (encrypted cache + key)
|
|
558
|
+
".preship-cache.json",
|
|
559
|
+
".preship-key"
|
|
533
560
|
]);
|
|
534
561
|
var MAX_FILE_SIZE = 1048576;
|
|
535
562
|
function walkProjectFiles(projectPath, allowPaths, scanPaths) {
|
|
@@ -571,7 +598,13 @@ function walkDirectory(rootPath, relativePath, files, allowPaths, scanPaths) {
|
|
|
571
598
|
if (SKIP_EXTENSIONS.has(ext)) {
|
|
572
599
|
continue;
|
|
573
600
|
}
|
|
574
|
-
if (
|
|
601
|
+
if (SKIP_FILENAMES.has(entry.name)) {
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
if (ext === ".lock") {
|
|
605
|
+
continue;
|
|
606
|
+
}
|
|
607
|
+
if (entry.name.endsWith(".min.js") || entry.name.endsWith(".min.css")) {
|
|
575
608
|
continue;
|
|
576
609
|
}
|
|
577
610
|
try {
|
|
@@ -642,9 +675,15 @@ async function scanSecrets(projectPath, config = {}) {
|
|
|
642
675
|
}
|
|
643
676
|
filesScanned++;
|
|
644
677
|
const isEnvFile = isEnvironmentFile(relativePath);
|
|
645
|
-
const
|
|
678
|
+
const skipEntropyRules = isEntropyNoisyFile(relativePath);
|
|
679
|
+
let candidateRules = getRulesForKeywords(content).filter(
|
|
646
680
|
(rule) => !mergedConfig.allowRules.includes(rule.id)
|
|
647
681
|
);
|
|
682
|
+
if (skipEntropyRules) {
|
|
683
|
+
candidateRules = candidateRules.filter(
|
|
684
|
+
(rule) => rule.id !== "high-entropy-base64" && rule.id !== "high-entropy-hex"
|
|
685
|
+
);
|
|
686
|
+
}
|
|
648
687
|
if (candidateRules.length === 0 && !isEnvFile) {
|
|
649
688
|
continue;
|
|
650
689
|
}
|
|
@@ -741,7 +780,28 @@ function redactSecret(value, rule) {
|
|
|
741
780
|
}
|
|
742
781
|
function isEnvironmentFile(relativePath) {
|
|
743
782
|
const basename2 = path2.basename(relativePath);
|
|
744
|
-
|
|
783
|
+
if (isEnvTemplateFile(basename2)) {
|
|
784
|
+
return false;
|
|
785
|
+
}
|
|
786
|
+
return basename2 === ".env" || basename2.startsWith(".env.");
|
|
787
|
+
}
|
|
788
|
+
function isEnvTemplateFile(basename2) {
|
|
789
|
+
const lower = basename2.toLowerCase();
|
|
790
|
+
return lower === ".env.example" || lower === ".env.sample" || lower === ".env.template" || lower === ".env.defaults" || lower === ".env.dist" || lower.endsWith(".example") || lower.endsWith(".sample") || lower.endsWith(".template");
|
|
791
|
+
}
|
|
792
|
+
function isEntropyNoisyFile(relativePath) {
|
|
793
|
+
const ext = path2.extname(relativePath).toLowerCase();
|
|
794
|
+
const basename2 = path2.basename(relativePath).toLowerCase();
|
|
795
|
+
if (ext === ".css") return true;
|
|
796
|
+
if (basename2.endsWith(".bundle.js") || basename2.endsWith(".chunk.js")) return true;
|
|
797
|
+
if (basename2.includes("manifest") && (ext === ".json" || ext === ".js")) return true;
|
|
798
|
+
if (basename2.includes("webpack") && ext === ".js") return true;
|
|
799
|
+
if (basename2 === "build-manifest.json") return true;
|
|
800
|
+
if (ext === ".svg") return true;
|
|
801
|
+
if (ext === ".json" && basename2 !== ".env.json") {
|
|
802
|
+
return false;
|
|
803
|
+
}
|
|
804
|
+
return false;
|
|
745
805
|
}
|
|
746
806
|
function hasEnvSecretContent(content) {
|
|
747
807
|
const lines = content.split("\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@preship/secrets",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Secrets detection for PreShip — find leaked API keys, tokens, and credentials before shipping",
|
|
5
5
|
"author": "Cyfox Inc.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -21,6 +21,6 @@
|
|
|
21
21
|
"lint": "tsc --noEmit"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@preship/core": "2.0.
|
|
24
|
+
"@preship/core": "2.0.1"
|
|
25
25
|
}
|
|
26
26
|
}
|