AfterPack threat model: सुरक्षित surface

AfterPack का security-review दस्तावेज़: वह किस asset की रक्षा करता है, हर attacker class क्या recover करती है, एक secret कैसे बचता है, मौजूदा scope कहाँ ख़त्म होता है, और किन controls के साथ यह काम करता है।

AfterPack एक asset की रक्षा करता है: वह JavaScript artifact जो आपकी build बनाती है। यह उस artifact को इस तरह फिर से लिखता है कि उसे पढ़ना, fingerprint करना या patch करना attacker के लिए असली मेहनत हो, और एक build के लिए बनाए गए tools अगली build पर टूट जाएँ।

यह पेज security review में पढ़ने के लिए लिखा गया है। यह बताता है कि किस surface की रक्षा होती है, हर attacker class क्या recover करती है, किस बिंदु पर build-time control काम करना बंद कर देता है, और बाक़ी को कौन-से controls संभालते हैं।

सुरक्षित surface

किसकी रक्षा होती हैकौन-सा attack संभव नहीं रहताकौन-सी property यह काम करती है
आपके ship किए bundle की पठनीयताBundle को किसी tool या model में paste करके अपना source वापस पा लेनाIdentifiers rename किए जाते हैं, strings encode की जाती हैं, control flow flatten किया जाता है और identities fuse की जाती हैं, इसलिए bundle को पढ़कर अपने source तक वापस पहुँचने में असली मेहनत लगती है, जो हर build पर दोबारा करनी पड़ती है
आपके bundle की संरचनाएक बार deobfuscator, signature या patch script लिखकर हर release पर दोबारा इस्तेमाल करनाहर build के लिए नया seed, इसलिए एक build के patterns के लिए लिखे गए tools अगली build पर टूट जाते हैं
आपके implementation का attributionयह साबित करना कि ship किया गया bundle आपका code, आपकी library या आपका algorithm हैनतीजे को आपके code से मिलाने से पहले static reader को हर build पर renamed & encoded recovery का काम दोबारा करना पड़ता है; provenance नष्ट करने वाली वे classes, जो इस मिलान को पूरी तरह हटा देतीं, आज नहीं बनतीं
String सामग्री जिससे आप तुलना करते हैंकिसी token या gate string के लिए bundle को grep करनाString floor, और equality gate के लिए non-materialization। light पर numbers पढ़े जा सकते हैं
इस्तेमाल में artifact की integrityएक check को patch करके patched build ship करनानया seed हर release में patch की जगह बदल देता है। Self-integrity केवल अपनी check table में किए गए बदलाव पकड़ता है

नीचे की हर बात इन पाँच rows को स्पष्ट करती है: किसे हराना है, हर property कितनी दूर तक पहुँचती है, और वह कहाँ नहीं पहुँचती।

Attacker classes

दो axes, एक scale नहीं। एक static attacker bytes पढ़ता है: grep, AST tooling, एक deobfuscator pass, या एक frontier model जो code को चलाए बिना समझाता है। एक dynamic attacker artifact को चलाता है: patched runtime में, built-ins को hook करके, या offline replay किए गए recorded execution trace के विरुद्ध। एक transform पढ़ने वाले के विरुद्ध मज़बूत और चलाने वाले के विरुद्ध कमज़ोर हो सकता है, और दोनों को एक मान लेना इस category का सबसे आम बढ़ा-चढ़ाकर किया गया दावा है।

नीचे की सीढ़ी attacker की क्षमता के क्रम में है। लागत दूसरी rows की तुलना में है, कोई absolute आँकड़ा नहीं।

पायदानAttackerScopeAttacker की लागतनतीजा
A0Static pattern tools: grep, AST matchers, deterministic deobfuscator passesएक buildमामूलीजो plaintext में बचा है, वही recover होता है। मौजूदा deobfuscators grep से ज़्यादा कुछ नहीं निकालते (मापे गए नतीजे)।
A1एक blind model: एक बार पढ़ना, कोई execution नहीं, कोई tools नहींएक buildमामूलीजो पढ़ा, उसका ज़्यादातर हिस्सा reverse कर लिया: तीन छोटे programs पर इसने light पर तीनों, medium पर दो और extreme पर एक को पूरी तरह reverse किया, और जहाँ यह चलने वाला program दोबारा नहीं बना सका, वहाँ भी इसने ज़्यादातर planted secrets recover कर लिए (मापे गए नतीजे)।
A2Execution, tooling और budget वाला एक agentic modelएक buildकम, हर build परउस build के लिए हार: code चलाने से उसकी values सामने आ जाती हैं। उस build की बनावट पर बने tools अगली build के लिए दोबारा बनाने पड़ते हैं।
A3AfterPack के अपने output के बड़े sample पर trained एक modelपूरा distribution, एक build नहींएक बार का निवेश, फिर हर build पर नगण्यमापा नहीं गया। नीचे देखें।
A4Instrumented dynamic analysis: hooked built-ins, recorded execution, heap snapshotsएक build, सस्ते में दोहराने योग्यAnalyst का समय, हर build परStrings के लिए नहीं टिकता: एक runtime hook ने हर preset पर 97 में से 96 recover कीं (मापे गए नतीजे)। देखें सीमा।
A5एक privileged runtime: patched browser, JavaScript layer से नीचे native hooksएक buildऊँचा setup, फिर नगण्यनहीं टिकता, client-side किसी भी चीज़ के लिए।

पायदान क्षमता में cumulative हैं, संभावना में नहीं। A0 ship किए गए JavaScript पर होने वाले असली attacks के भारी बहुमत को कवर करता है: कोई free tool चलाता है या आपका bundle किसी chat window में paste कर देता है। A5 एक दुर्लभ, महँगा endgame है जिसका ज़्यादातर products को कभी सामना नहीं होता।

A0 से A2 एक build पर attack करते हैं। जब तक आप seed pin न करें, हर build का नया seed बनावट बदल देता है, इसलिए एक build के लिए लिखा गया recognizer या patch अगली build के लिए दोबारा लिखना पड़ता है। यह values नहीं छिपाता: code जो भी इस्तेमाल करता है, उसे चलाने वाला पढ़ सकता है।

A3 पूरे output distribution पर attack करता है। पर्याप्त बड़े sample पर trained model per-build variance के प्रति invariant होना सीख लेता है, और आपका seed rotate करने से उसे कोई फ़र्क नहीं पड़ता। जो फिर भी मदद करता है वह है निशाना: Pro आपके mark किए regions पर भारी preset लगाता है और दो opt-in transform kinds जोड़ता है, transforms.selfIntegrity.enabled और transforms.comparisonHardening.enabled। जो सच में मायने रखता है उसे mark करें; देखें Best practices।

A4 और A5 static artifact को पूरी तरह छोड़ देते हैं। सीमा दोनों को कवर करती है।

मापे गए नतीजे

Engine 0.2.2 के output से हर attacker ने क्या recover किया। अक्टूबर 2026 में मापा गया, planted secrets वाले पाँच programs और असली production bundles पर। Frontier model वाली row अक्टूबर 2026 में engine 0.2.6 पर किया गया एक अलग run है।

Attackerlightmediumhard और extreme
Pattern tools: webcrack, restringer, synchrony, tersergrep से ज़्यादा कुछ नहींgrep से ज़्यादा कुछ नहींgrep से ज़्यादा कुछ नहीं
42 planted numbers के लिए grep421818
Output का static evaluation92–100% stringsbehavior बनाए रखने वाले clean-up pass के बाद 96–98% stringsउसी pass के बाद 96–98% strings
किसी built-in पर 15 lines का runtime hook97 में से 96 strings97 में से 96 strings97 में से 96 strings
एक frontier model, blind, बिना tools, बिना executionतीनों programs पूरी तरह reverse3 में से 2 पूरी तरह reverse; तीसरे ने 17 में से 12 secrets दे दिए, पर चलने वाला rebuild नहीं बनासिर्फ़ extreme: 3 में से 1 पूरी तरह reverse (9 में से 9 secrets); बाकी दो ने 17 में से 12 और 3 में से 2 secrets दे दिए, पर चलने वाले rebuild नहीं बने

Frontier model वाली row में Claude Opus 5.5 को सिर्फ़ obfuscated file मिली, और जिन 5 files को उसने मना किया, वे Claude Opus 4.8 को दी गईं; "पूरी तरह reverse" का मतलब है कि दोबारा बनाया गया code original वाले ही test vectors print करता है और उसमें हर planted secret मौजूद है। सीमाएँ: तीन programs का छोटा corpus, हर program और preset पर एक ही attempt, और attacker सिर्फ़ Claude।

Obfuscation किसकी रक्षा करता है

AfterPack दो गुणों को लक्ष्य बनाता है। पहला है लागत: किसी build को reverse करने की लागत उससे ज़्यादा होनी चाहिए जिसकी वह रक्षा करता है। दूसरा है release-cadence का फ़ायदा: आपकी update की रफ़्तार उस रफ़्तार से तेज़ है जिससे attacker के tools अगली build पर लागू होना सीखते हैं। कोई भी obfuscator, AfterPack समेत, reversal को असंभव नहीं बनाता, और इस पेज की किसी बात को ऐसा दावा न समझें।

डिफ़ॉल्ट preset identifiers को rename करता है और string literals को encode करता है। medium और ऊपर, AfterPack इससे ज़्यादा करता है: control flow को flatten किया जाता है, identities को fuse किया जाता है, और logic को ऐसे समतुल्य रूपों में दोबारा लिखा जाता है जिन्हें आम tools वापस नहीं समेट पाते। उस output को reverse करने वाला attacker एक चलता हुआ program recover कर सकता है, लेकिन केवल उस असली pattern-recognition के काम के बाद जिसकी लागत ये transforms लगाते हैं, और एक build की बनावट के लिए लिखा गया tool अगली build पर टूट जाता है। Reversal classes इसे उन classes में बाँटता है जिनका सामना एक static reader करता है।

Per-build seed default रूप से random है, इसलिए एक ही source की दो builds हर जगह संरचना में अलग निकलती हैं। Build N के patterns के लिए लिखे गए tools build N+1 पर टूट जाते हैं, जबकि build N से कोई जो values पढ़ चुका है, वे पढ़ी जा चुकी रहती हैं। यह गुण तभी काम आता है जब आप builds rotate करें; Best practices और Builds और CI बताते हैं कि rebuilds को release pipeline में कैसे जोड़ें।

इनमें से कुछ भी अपने आप में किसी secret को नहीं छिपाता। उसके लिए एक अलग mechanism चाहिए।

एक secret की रक्षा

Secret किसी भी ऐसे program से निकल आता है जो आपके program जैसा व्यवहार करता है, उस program से भी जिसे एक static reader किसी protected region से recover करता है। Secret के आसपास के code को नया आकार देना इसके लिए कुछ नहीं करता।

Bytes पढ़ने वाले से secret की रक्षा non-materialization करता है, जिसे Secrets कैसे बचते हैं में कवर किया गया है। इसे देने वाली setting, transforms.comparisonHardening.enabled, एक Pro setting है, डिफ़ॉल्ट रूप से बंद, और हर preset स्तर पर एक जैसा काम करती है।

जो आपका code चलाता है उसके विरुद्ध सीमा लागू होती है। Per-build variance हर rotation पर secret को दोबारा निकालने की लागत बढ़ाता है। JavaScript engine पर लक्षित एक generic runtime hook की लागत फिर भी उतनी ही रहती है, क्योंकि वह AfterPack की संरचना पर निर्भर नहीं करता। AfterPack कैसे काम करता है इसी mechanism को उसके साथ रखता है जो standard output पहले से करता है।

सीमा

जो attacker आपका code एक instrumented runtime में चलाता है, वह किसी भी ऐसी value तक पहुँच सकता है जिसे code खुद इस्तेमाल करता है। अगर चलते program को उसकी ज़रूरत है, तो एक दृढ़ dynamic attacker उसे देख सकता है। AfterPack उस value को खोजना महँगा और उससे दूर rotate करना सस्ता बनाता है। यह उसे unrecoverable नहीं बनाता।

Server-side authority को client से दूर रखें

Signing keys, लंबे समय तक चलने वाले credentials, और कोई भी चीज़ जिसे attacker दोबारा इस्तेमाल कर सके या बेच सके, server पर होनी चाहिए, चाहे आप कोई भी obfuscator इस्तेमाल करें।

यह सीमा केवल AfterPack की नहीं है। जैसे ही attacker runtime पर नियंत्रण कर लेता है, हर build-time obfuscator इसी दीवार से टकराता है। उस दीवार के पार AfterPack अगली release की बनावट बचाए रखता है: एक build के लिए बनाए गए tools उसके बाद वाली build के लिए दोबारा बनाने पड़ते हैं।

Anti-tamper

Self-integrity, transforms.selfIntegrity.enabled, अपनी ही check table पर एक check जोड़ता है। यह केवल उस table में किए गए बदलाव को पकड़ता है। आपके code में कहीं और किया गया बदलाव, जैसे patch किया गया return true, पकड़ा नहीं जाता।

यह passive observation भी नहीं पकड़ता: values log करने वाला hook, heap read या native instrumentation उसकी जाँची जाने वाली किसी चीज़ को नहीं बदलते। यह एक Pro setting है, default रूप से बंद और global, और इसे जुड़ने के लिए medium या उससे ऊपर का code चाहिए, इसलिए light build में यह केवल उसी region के अंदर होता है जिसे उस स्तर तक बढ़ाया गया हो। preset=hard इसे बंद छोड़ता है और इसके बजाय एक region को complexity target 12 तक ले जाता है, string floor चालू रखते हुए।

AfterPack किसकी जगह नहीं लेता

AfterPack एक stack में एक control है, और security review को उसकी सीमाएँ दिखनी चाहिए। नीचे की हर row build-time control का मौजूदा scope और बाकी को कवर करने वाला control बताती है। Product के ship होने के साथ scope बदलता है; public roadmap ही वह एकमात्र जगह है जहाँ AfterPack बताता है कि आगे क्या आ रहा है।

Controlआज AfterPack का योगदानबाकी को क्या कवर करता है
Request-layer defense (bots, scraping, abuse)जो scraper आपके bundle से structured data चाहता है, उसे पहले उसे reverse करना होगा। AfterPack artifact पर काम करता है और request को नहीं देखता।एक challenge-response service (reCAPTCHA, hCaptcha, Arkose), साथ में IP, session या API key पर आधारित server-side rate limiting।
Client integrity (cheating, automation, patched clients)preset=hard, per-build-polymorphic client के विरुद्ध काम करने वाले cheat या automation लेखक को किसी ज्ञात offset को एक बार patch करने के बजाय हर release पर असली analysis दोबारा करना पड़ता है। AfterPack यह लागत बढ़ाता है; यह फ़ैसला नहीं करता।Hits, state transitions और outcomes का server-authoritative validation, जिसमें client केवल उन फ़ैसलों को render करता है जो server पहले ही ले चुका है।
Delivery integrity (proxies, CDNs, extensions)AfterPack अपने बनाए bytes की रक्षा करता है। यह उनके रास्ते को नियंत्रित नहीं करता, और browser की अपनी request-blocking API इस्तेमाल करने वाला extension किसी भी JavaScript के चलने से पहले तय कर लेता है कि क्या load हो।Subresource Integrity (integrity="sha384-…"), ताकि browser ऐसे bundle को अस्वीकार करे जो आपके build किए hash से मेल न खाए, साथ में उस हर चीज़ का server-side validation जिसे कोई intermediary प्रभावित कर सके।
Application security (bugs, injection, broken auth)Obfuscation source पढ़कर किसी flaw को खोजने की गति धीमी करता है। यह flaw को हटाता नहीं, और जो चलते program के ज़रिए उस तक पहुँचता है वह आपका source कभी पढ़ता ही नहीं।Bug ठीक करें। npx afterpack@latest audit एक live site को scan करके बताता है कि वह पहले से क्या leak कर रही है।
Client के बारे में trust के फ़ैसलेPer-build polymorphism एक बार के patch को बार-बार दोहराई जाने वाली re-derivation लागत में बदल देता है।Server-authoritative validation, नीचे।

Server-authoritative validation का विकल्प नहीं

ऊपर की हर row की जड़ एक ही है: एक license check, payment gate, entitlement rule, या feature flag जिसे सच में टिकना है, वह एक ऐसा फ़ैसला है जो client अपने बारे में खुद लेता है, और जो उस client को नियंत्रित करता है वह उसे जाली बना सकता है। यह client-side execution की property है, किसी खास obfuscator की कमी नहीं, और कोई भी build-time transform इसे बंद नहीं करता।

जो कुछ भी एक शत्रुतापूर्ण client के विरुद्ध टिकना चाहिए, जैसे licensing, payments, entitlements या match outcomes, उसका फ़ैसला server-side लें और client को केवल उसे दिखाने दें। AfterPack का योगदान आर्थिक है, और यह असली है: यह client पर चलने वाली चीज़ों पर attack करने की बार-बार की लागत बढ़ाता है।

आगे

  • Attacker क्या recover कर सकता है: static-attacker classes विस्तार से, diagram के साथ।
  • AfterPack कैसे काम करता है: standard output पहले से आपके bundle के साथ क्या करता है।
  • Protection Map: अपनी build में जाँचें कि कौन-सी class किस लाइन पर लागू हुई।
  • Best practices: क्या mark करें, क्या rotate करें, और क्या server-side रखें।
  • Privacy & data handling: आपकी मशीन से क्या बाहर जाता है, क्या store होता है, और कितने समय तक।
  • Audit: एक live URL को उन leaks के लिए scan करें जिन्हें obfuscation पलट नहीं सकता।
  • Comparison: AfterPack उन tools से कैसे अलग है जिन्हें आप पहले से जानते हैं।
  • Tiers: Free पहले से कौन-से पायदान कवर करता है, और Pro क्या जोड़ता है।