Description: "8,432 lines of Python, 200 bit-flips, 460 fuzzed inputs, and one honest flaw. Here's what happened when I attacked ATLOCK v5 before releasing it."
TL;DR: I built a single-file security suite in pure Python. Before release, I locked it in a clean virtual environment and tried to wreck it. Most things held. One thing made me frown. You can try the current version (v4) today, and v5 is already built and waiting for a milestone. 👇
🎬 The setup
Everyone says "my tool is secure." Almost nobody publishes the receipts.
So I did something slightly uncomfortable: I took ATLOCK v5 (not public yet), dropped it into a fresh venv, and attacked it like a stranger would. No GUI clicking, no gentle demos. Raw crypto functions, corrupted files, wrong passwords, forged keys.
python -m venv atenv && source atenv/bin/activate
pip install cryptography argon2-cffi pillow numpy qrcode requests
python ATLOCK_v5.py --selftest
First, some context on what we're even looking at:
| ATLOCK v4 (public today) | ATLOCK v5 (built, unreleased) | |
|---|---|---|
| Size | 3,074 lines · 23 classes | 8,432 lines · 55 classes |
| File encryption | Fernet (AES-128-CBC + HMAC) | AES-256-GCM, chunked, key-committing |
| Password hashing | PBKDF2-SHA256, 200k iterations | Argon2id (64 MiB floor, 128 MiB for vault) |
| Sharing files | none | X25519 + Ed25519 public-key encrypt & sign |
| Recovery | none | Shamir secret sharing (3-of-5) |
| 2FA | none | TOTP + FIDO2 hardware keys |
| Built-in self-test | none | 33 checks + a corruption fuzzer |
Fun fact: v5 is nearly 3x the code of v4. So the real question was: did the extra code add security, or just extra places to crash?
🧪 Round 1: The built-in self-test
$ python ATLOCK_v5.py --selftest
[OK] Zip-slip / traversal names rejected
[OK] Doctored-header KDF ceiling is enforced (no DoS via .atl file)
[OK] Empty (0-byte) file container round-trips
[OK] Recovery key split into shares (3 of 5) rebuilds exactly
[OK] Frozen v1 / v2 / v3.0 containers from ATLOCK 5.0 still open
...
----------------------------------------
ALL PASSED (33/33)
Passing your own tests is the easy part, of course. So I stopped trusting them and wrote my own.
💥 Round 2: Try to corrupt it
The attack: seal a 5 MB random file, then flip one random bit, anywhere in the encrypted blob. Do that 200 times. If even one flip decrypts to wrong data without complaint, that's silent corruption, the nightmare scenario.
bitflip_200: rejected=200 silent_corruption=0 unexpected_crash=0
truncation (5 cut points): rejected=5/5
wrong password: AtlockAuthError
same input sealed twice -> different ciphertext: True
200 out of 200 rejected. Zero silent corruption. Zero crashes.
Then I let the built-in fuzzer loose:
$ python ATLOCK_v5.py --fuzz 300
fuzzed 300 container mutations, 100 garbage shares, 60 junk imports:
no crashes, no silent corruption.
That's 460 hostile inputs, no drama.
⚡ Round 3: Is it slow? (Security that's painful gets switched off)
| Operation | Result |
|---|---|
| Seal 5 MB file | 0.77 s |
| Open 5 MB file | 0.63 s |
| Container overhead | 134 bytes |
| Argon2id (64 MiB, t=3) | 0.16 s |
| Argon2id (128 MiB, t=4, vault) | 0.45 s |
| PBKDF2 200k (what v4 uses) | 0.05 s |
This is the part I find genuinely interesting. v4's PBKDF2 takes ~50 ms. An attacker with a GPU rig loves that. v5's Argon2id makes each guess cost 128 MiB of RAM, which is exactly what GPUs are bad at. Same login delay for you, a far worse deal for them.
🔐 Round 4: Public-key mode (the new toy)
Two identities, Alice and Bob. Alice encrypts and signs a file for Bob.
| Scenario | Outcome |
|---|---|
| Bob decrypts | ✅ works, signature verified |
| Alice tries to open Bob's file | ❌ "encrypted for a different identity" |
| Flip one byte in the file | ❌ rejected |
| Edit the file after signing | ❌ signature check fails |
| Shamir: any of the 10 possible 3-of-5 combos | ✅ rebuilds the key exactly |
| Shamir: only 2 shares | ❌ refused |
Everything behaved. Except...
😬 The thing I'm not happy about
I tested sender pinning: Bob says "I only trust files from this key," then I hand him a file signed by someone else.
>>> atl_pk_decrypt_file(enc, out, "bobpass", expected_sender_pub=wrong_key)
{'signed': True, 'signer_matches': False}
It decrypted anyway. The app shows WARNING: this is NOT the sender key you pasted!, but it does not stop.
Is that a bug? Honestly, it's a design choice, and I can argue both sides:
- Warn-only: the user stays in control, and you might genuinely want to read a file first and ask the sender later.
- Hard-fail: if you pinned a key, you already told the app you don't want anyone else. A warning is a polite way to get ignored.
I lean towards hard-fail when a key is pinned. Where do you land? This is my real question for the comments. 👇
🔎 Other things the scan flagged
I ran bandit over both files:
| v4 | v5 | |
|---|---|---|
| High | 0 | 1 |
| Medium | 0 | 3 |
- The 1 "High" is SHA-1, used for the Have I Been Pwned password check. That API requires SHA-1, and only the first 5 characters of the hash ever leave your machine (k-anonymity). Flagged, explained, fine.
-
The 3 "Mediums" are
urlopencalls. Worth pinning URL schemes in the final release. Noted.
Also caught a docs bug while reading: the v5 header still says "UI is unchanged from v5". A copy-paste leftover from earlier versions. Embarrassing, tiny, getting fixed.
🧱 What I did NOT test (be honest, right?)
ATLOCK is Windows-first, and my sandbox was Linux. So:
- ✅ Tested: all crypto, container format, fuzzing, Shamir, public-key, signatures, CLI
- ❌ Not tested here: the GUI, Windows Hello, DPAPI (falls back to a dev mode off-Windows), BitLocker checks, camera/intruder capture, the startup watchdog, FIDO2 with a real YubiKey
The project's own docs say it plainly too: a pure-Python tool cannot stop an attacker who is already running code as you, and secure-delete can't be guaranteed on SSDs. ATLOCK raises the cost; it doesn't claim magic. I'd rather you hear that from me than discover it later.
🚀 Try it, then come back for v5
ATLOCK v4 is public right now:
Here's the deal I'm offering:
- Grab v4 and try it for a few days. Lock a file. Break a password on purpose. Tell me what annoys you.
- Wait a little. v5 is already finished (everything above came from it), but I'm releasing it when Akhouri Systems crosses 1,000 downloads.
- Right now we're at 910. That's 90 downloads away. 🎯
When it lands, you upgrade to Argon2id, AES-256-GCM, hardware-key 2FA and public-key encryption, with your existing v4 habits intact.
💬 Let's argue (nicely)
I'd really like your takes on these:
- Pinned sender key doesn't match: warn or hard-fail?
- Would you trust a pure-Python security tool with real files, or does that make you nervous? Be brutal.
- Argon2id at 128 MiB: too heavy for older laptops, or still not enough?
- What would make you switch from your current vault or file locker?
Drop a comment. The best criticism ends up in the v5 changelog with your name on it. 🏷️
Built by Akhouri Anmol Kumar · An Akhouri Systems product
Top comments (21)
Really nice write-up. I especially appreciate that you included what you did not test — that makes the security claims much more credible.
On sender pinning, I’d strongly prefer hard-fail.
If expected_sender_pub is explicitly provided, that is no longer just informational metadata; it is a security policy. Returning successfully with signer_matches=False means the cryptographic layer detected a policy violation but left enforcement to the caller/UI.
I’d probably make the semantics explicit:
That also makes the API safer for future integrations where there may be no human around to notice the warning.
One other thing I’d test before v5: make sure authentication happens before any plaintext becomes observable, especially with chunked AES-GCM. Corrupting random bits is a great test, but deliberately targeting chunk boundaries, lengths, nonces, tags, reordered/duplicated chunks, and the final truncated chunk would be interesting too.
Overall, publishing the failure cases alongside the successful tests is exactly the kind of security engineering write-up I like seeing. 👍
Thank you brooo, this is exactly the review I was hoping for. I ran your chunk-level attacks: 91 targeted mutations (length prefixes, tags, reordering, duplication, dropped and truncated final chunks, cross-seal splices) were all rejected, and 82/82 header bit-flips with the hash recomputed were rejected toooo,
Your pinning point turned out to be worse than I'd written: a pinned sender with an unsigned file also decrypted silently. V5 now fails closed with a dedicated exception, and an explicit override is required to decrypt anyway.
You also made me look at plaintext release: the streaming path hands out authenticated chunks before later ones are verified, and one viewing helper left partiaL plaintext on Disk after A failure. Both are fixed....:)
Hahaha, now this is why I enjoy security reviews. 😄
I came looking for one pinning edge case and somehow we ended up finding an unsigned-sender path, streaming plaintext exposure, and partial plaintext left on disk after failure.
That’s a very productive rabbit hole. 😂
More importantly, huge respect for actually testing the suggestions, publishing what you found, and fixing the behavior instead of defending the original design.
This is exactly how security software should mature. 🔐👍
I especially published the post and commented on post to trigger you
"Mustafa ERBAY hehehe" because I know you will use your security top tier mind and give me feedbacks, and more.
Bro Can I mention you later when ATLOCK v5 will publicly released in ATLOCK v5 repo your name?
Also Bro How can i make this post viral too?
mustafa bro, should I port ATLOCK v5 for linux and mac too?
currently it is only for windows.
reply?
Hahaha, I knew that “Mustafa ERBAY hehehe” was bait. 😂
You deliberately triggered the security-review daemon, and unfortunately for you, it worked.
And yes, of course you can mention me in the v5 repo when it’s released. I’d actually be happy to be mentioned for the review/testing feedback — just keep it factual; I don’t want to accidentally become “ATLOCK independently audited by Mustafa” 😂. I reviewed a few design assumptions and helped you find some edge cases. That’s the accurate description.
About Linux and macOS: yes, I think you should port it, but don’t try to reproduce every Windows-specific feature immediately.
First make the crypto/container core truly cross-platform:
Then put platform-specific security behind separate adapters: DPAPI/Windows Hello on Windows, Keychain/Secure Enclave where appropriate on macOS, and Secret Service/keyring or equivalent mechanisms on Linux.
Most importantly: the same .atl file should open on Windows, Linux and macOS. One format, one crypto behavior, different OS integrations.
And for making the post viral: don’t optimize for “viral.” You accidentally found the better formula already. 😂
“I built a security tool” is ordinary.
“I asked people to break my security tool, they found assumptions I had missed, I reproduced them, fixed them, and added regression tests” is a story.
When v5 launches, publish the before/after evidence. Show exactly what failed, what changed, and which tests now prevent regression. Security people love receipts more than marketing.
Now stop summoning me by name unless you’re prepared to add more tests. 😂🔐
Really good write-up. What I like most is that you didn’t stop at “all tests passed.” You started attacking the assumptions behind the system.
That distinction is important in security. A function can behave correctly under normal tests while the overall flow still has a dangerous edge case.
The plaintext-release issue is a great example of that. Authentication can be correct at the chunk level, but if the system exposes part of the plaintext before the full verification flow finishes, the security property of the whole operation changes.
I’ve seen the same pattern outside file encryption too. For example, an API can successfully authenticate a request, but if it starts processing or exposing sensitive data before authorization is fully resolved, the individual checks may all be “working” while the system is still wrong.
That’s what makes this kind of adversarial testing valuable: you’re not only asking “does this function reject bad input?” You’re asking “at what point does the system actually trust the data?”
And honestly, publishing the failures and then showing how the design changed because of them makes this much more useful than a typical “my security tool passed 100% of its tests” post. 🔐
Thanks, and that's what make ATLOCK different.
Have you downloaded v4? if not then it's okay you can wait for v5.
v5 is coming soon.
Appreciate you publishing the receipts, especially the sender-pinning result. Most "I tested my own tool" posts only show the wins.
Warn or hard-fail on a pinned key: hard-fail, and I don't think it's close. Pinning is an explicit statement of intent, and
expected_sender_pubis the caller saying "reject anyone else." A warning only helps if a human reads it, and the return value{'signed': True, 'signer_matches': False}is exactly the shape that gets ignored by a script or a wrapper UI that checkssignedand moves on. That's a classic fail-open pattern. I'd do three things:AtlockSenderMismatch) when a pin is supplied and doesn't match.outbefore the sender check passes. If the file has already been decrypted to disk, the warning is cosmetic.allow_unpinned_sender=Trueor a separateinspectmode, so the permissive path is a deliberate choice rather than the default.The GUI can still offer an "I understand, open anyway" button on top of that. The API should be strict and the UI can be forgiving, not the other way around.
Pure-Python trust: the language matters less than what's underneath. If the primitives come from
cryptographyandargon2-cffi(both wrap audited C libraries), I'm not worried about timing or implementation bugs in AES-GCM or Argon2 themselves. My concerns are different:requests,pillow,numpyandqrcodehas a larger dependency surface than a vault needs. Consider splitting the crypto core from the optional features so the core can be audited on its own.Argon2id at 128 MiB: fine for most laptops from the last ~8 years, but I'd make it adaptive rather than fixed. Benchmark on first run, store
m,t,pin the header, and target something like 0.3 to 0.5 s on that machine. A low-RAM device could then use a lower floor with a clear warning, and you could raise parameters over time with a rekey-on-open path. Your doctored-header KDF ceiling check is a good sign you've already thought about the flip side, a malicious file demanding absurd memory.A few other notes from the post:
urlopenMediums, pinning tohttpsand rejecting other schemes is the right fix, and for the HIBP call, add a timeout and fail closed on errors rather than treating "couldn't check" as "not pwned."What would make me switch: a documented threat model, a reproducible build or signed releases, an independent review (even informal), and a stable, documented container format so files stay readable years from now. Your frozen v1/v2/v3.0 compatibility test is the right instinct there.
Good luck on the way to 1,000. Looking forward to seeing the v5 changelog.
Thanksss, bro.. for the careful read, this is the most useful feedback the post got. Going through it:
Sender pinning: I agree, hard-fail. That's how it works in v5: if you pin a sender key and the file is unsigned or signed by someone else, it raises AtlockSenderMismatch before any plaintext is written. Reading it anyway needs an explicit allow_sender_mismatch=True. I've added a self-test that checks no output file is left behind on a mismatch..
Chunk attacks: Good point, the 200 bit-flips mostly test the GCM tag. Each chunk already binds the header hash, its index and a final-chunk flag, but I hadn't tested that properly. The self-test now covers:
a bit-flip in every header byte
chunk reorder, duplication, drop and an extra chunk
truncation exactly on a chunk boundary
a prefix of a file never opening as a whole file
urlopen / HIBP: All three calls now go through one helper that refuses any non-https URL, including redirects to one. A breach check that can't run (offline, timeout, bad reply) now shows as "could not check, not verified" instead of "safe". It used to fall through to "safe", which was a real bug.
Argon2: It's already benchmarked per machine, with m/t/p stored in each file header and a ceiling that rejects doctored headers. I lowered the target to about 0.5 s and added a warning on very slow machines. Rekey-on-open to raise parameters over time isn't built yet.
Docs: The docstring now says plainly that there's been no third-party audit (the self-test and fuzzing are my own), has a short threat model, notes that Python can't reliably wipe secrets from RAM, and explains key commitment.
Not done: Splitting the crypto core into its own auditable module. The core only needs cryptography and argon2-cffi, but it's still one file today. It's on the list.
Thanks again.... :)
@akhourianmolkumar Bro, this is the spirit of true engineering.
"I tried to break it... it fought back." That is the best compliment a security tool can receive. If it doesn’t fight back, it’s useless.
Finding "1 thing you’re not happy about" is actually a win. Most people hide those flaws until they explode in production. You surfaced it now, while you can fix it.
KODA and ATLOCK are siblings in chaos. I’m shipping fast and fixing bugs in hours; you’re stress-testing boundaries and finding cracks. We are covering the full spectrum of HYNAWEB: Velocity + Resilience.
Drop the link when you patch that flaw. I’ll be first in line to test it against my Worker’s injection defenses. Let’s see if KODA’s 1µs regex filter can catch what ATLOCK misses. 😂️🐯
KODA & ATLOCK
2 greatest product ever made by 12-13
You may refer to Jev, which works like an access control system. If identity verification fails, it blocks the operation entirely rather than just showing a warning.
I will definitely look at it.
bro how can I make this post viral too
There’s no guaranteed trick to make a post go viral. Virality relies on a mix of topic, headline, timing and luck.
Your security suite project is interesting. Try writing a hands‑on article about breaking your own ATLOCK, similar to this post. Stories about finding flaws and fixing them always attract developers. But don’t chase virality as your main goal. Focus on telling a genuine technical story first.
yeah, that's the point.
Mustafa ERBAY just helped me a lot.
due to him I fixed one flaw in ATLOCK v5.
Great to hear! External feedback is priceless for tightening up security tools 🔐
Mustafa ERBAY hehehe