@webdecoy/fcaptcha 1.13.0 → 1.14.0
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/package.json +1 -1
- package/server.js +34 -0
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -495,6 +495,39 @@ function detectHeadless(signals, userAgent) {
|
|
|
495
495
|
return detections;
|
|
496
496
|
}
|
|
497
497
|
|
|
498
|
+
// Flags anti-detection patch traces collected by the client. FALSE-POSITIVE-
|
|
499
|
+
// SAFE: a genuine browser never produces these (internal contradictions /
|
|
500
|
+
// native-function tampering, not environment-shape heuristics that would
|
|
501
|
+
// misfire on real Linux/VPN users). Targets stealth agents (e.g. Manus AI)
|
|
502
|
+
// driving real-but-patched Chromium. Only the two FP-safe signals are scored;
|
|
503
|
+
// the client also collects privacy-extension-ambiguous artifacts (patched_*)
|
|
504
|
+
// for observability that are intentionally NOT scored. Keep in sync with Go/Py.
|
|
505
|
+
function detectStealthArtifacts(signals) {
|
|
506
|
+
const detections = [];
|
|
507
|
+
const env = signals.environmental || {};
|
|
508
|
+
|
|
509
|
+
// Function.prototype.toString proxied — the signature move of stealth
|
|
510
|
+
// frameworks (used to make their other native overrides look untouched).
|
|
511
|
+
const artifactSignals = (env.stealthArtifacts && env.stealthArtifacts.signals) || [];
|
|
512
|
+
if (artifactSignals.includes('tostring_proxied')) {
|
|
513
|
+
detections.push({
|
|
514
|
+
category: 'headless', score: 0.9, confidence: 0.85,
|
|
515
|
+
reason: 'Function.prototype.toString is proxied (stealth automation patch)'
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Notification.permission === 'denied' while the Permissions API reports
|
|
520
|
+
// 'prompt': a state a real browser cannot reach (classic headless tell).
|
|
521
|
+
if (env.permissionProbe && env.permissionProbe.contradiction === true) {
|
|
522
|
+
detections.push({
|
|
523
|
+
category: 'headless', score: 0.85, confidence: 0.85,
|
|
524
|
+
reason: 'Notification permission contradicts Permissions API (headless/stealth tell)'
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return detections;
|
|
529
|
+
}
|
|
530
|
+
|
|
498
531
|
function detectAutomation(signals) {
|
|
499
532
|
const detections = [];
|
|
500
533
|
const env = signals.environmental || {};
|
|
@@ -1098,6 +1131,7 @@ function runVerification(signals, ip, siteKey, userAgent, headers = {}, ja3Hash
|
|
|
1098
1131
|
detections.push(
|
|
1099
1132
|
...detectVisionAI(signals),
|
|
1100
1133
|
...detectHeadless(signals, userAgent),
|
|
1134
|
+
...detectStealthArtifacts(signals),
|
|
1101
1135
|
...detectAutomation(signals),
|
|
1102
1136
|
...detectCDP(signals),
|
|
1103
1137
|
...detectBehavioral(signals),
|