Illustrated with AICybersecurity for Juniors · Book 2 · Chapter 3
The Group Project Repo
Part 1 · CampusConnect, due at 9 a.m.
Naina and Rehan's first real coding assignment was small on paper and enormous at 1 a.m.: a web form called CampusConnect, where students could submit feedback about hostel food, and the app would email a tidy weekly summary to the mess committee automatically.
The emailing part needed a transactional email service, the kind that hands out a free "API key," a long string of letters and numbers that proves to the service it's really your app asking it to send mail, and not someone else's.
They signed up, got their key, pasted it somewhere in the code that worked, and moved on, the way anyone does at 1 a.m. with a 9 a.m. deadline.
Part 2 · The 1 a.m. shortcut
"Somewhere in the code" turned out to be directly inside main.py, in plain text, right next to the line that sent the email: API_KEY = "sk_live_7hT9k2...". It worked immediately, which at 1 a.m. felt like the only thing that mattered.
Sanjeev sir's instructions asked them to push the finished project to a public GitHub repository, so he could clone it and check it ran. Rehan did exactly that, half-asleep, without a second thought for what else was sitting inside main.py the moment it went public.
"Submitted," he said, closing the laptop. "Sleep now, worry later."
Part 3 · A message from someone called quietpatch0x
Illustrated with AIThree days later, a notification landed on the CampusConnect repository: a new "issue," titled simply, "Please rotate your email API key, it's exposed in main.py." The message, from a GitHub account called quietpatch0x, was short, polite, and included a direct link to the exact line.
Naina's first reaction wasn't relief. It was suspicion. "Is this a scam?" she asked. "Someone messaging us out of nowhere, about a 'problem,' telling us to act fast?"
It did sound, uncomfortably, like the kind of message they'd learned to distrust by now. The difference, she realised on a second read, was that this one asked them to fix something themselves, on their own account, and wanted nothing from them in return. No link to click, no payment, no document.
Part 4 · Checking with Ananya didi, just in case
Ananya didi read the issue, then the code, then let out a small laugh that wasn't unkind. "It's real," she said. "And quietpatch0x did exactly the right thing. This is called responsible disclosure: finding a security problem and reporting it quietly to the people who can fix it, instead of using it, selling it, or posting it publicly for anyone to grab."
She pulled up the repository's commit history, still fully public. "Public GitHub repos get scanned constantly, by researchers, and by automated bots looking for exactly this pattern, 'sk_live_' followed by a long string. Some bots report it like quietpatch0x did. Others just use it. You got the better kind of attention first, this time."
Part 5 · Sanjeev sir, and the thing about git history
Illustrated with AISanjeev sir, once looped in, didn't lecture about the mistake itself, every student made it once. He wanted them to understand the part that surprised most people: "If you simply delete that line in a new commit, the key doesn't disappear. It's still sitting in an earlier commit, in the project's full history, which anyone can still browse."
He sketched it on the whiteboard: commit one has the key, commit two removes it, but commit one still exists, forever, unless someone deliberately rewrites history with a tool built for exactly that. "Treat any secret that's ever been committed as burned," he said. "Rotate it. Don't just hide it."
Part 6 · Rotating the key, properly this time
They logged into the email service and revoked the old key within the hour, generating a fresh one. This time, the key went into a separate file named .env, which they added to a new file called .gitignore, a list of files Git is told to never track or upload, ever.
The code itself changed by exactly one line: instead of a string typed directly in, it now read the key from the environment, os.environ.get("API_KEY"), invisible to anyone looking at the public code, present only on the machine actually running it.
Checking the service's usage logs, relief: the free-tier key had a strict sending cap, and nobody had used it for anything in the three days it sat exposed. "We got lucky," Naina said. "Lucky isn't a plan," Ananya didi replied, not unkindly.
Part 7 · Rehan wants to be quietpatch0x next
Rehan couldn't stop thinking about the message, less about the mistake it pointed out, more about the person who'd found it. "How does someone even find stuff like that?" he asked. "On purpose? Legally?"
"That's a whole world," Ananya didi said, amused. "Ethical hacking, done properly, with rules. Ask me again once you're sure you want the real answer, not just the exciting-sounding one."
Rehan was already sure. He just didn't yet know how close that curiosity would come to getting him into real trouble, barely a week later.
Moral of the story
A secret typed into public code is no longer a secret. The fix isn't hiding it better. It's never writing it there at all.
What's pushed in haste at one a.m.
stays written down for who, and when.
A key once shown to open eyes
must be replaced, not just disguised.
Spot the problems in this code
main.py, pushed at 1 a.m.
A snippet from CampusConnect's public repository:
No .gitignore file anywhere in the project. 3
Repository visibility: Public, visible to anyone on the internet. 4
A live API key, typed directly into the source code. Anyone who can see the code can now send email, or run up usage, on this account.
A database password, in plain text, right next to the key. One leaked file, two separate systems now exposed.
Nothing tells Git to keep sensitive files out of what gets uploaded, so anything created locally can end up public by default.
A public repository is scanned by bots within minutes of a push, looking for exactly these patterns. Public means public to everyone, immediately.
Field notes
What really happened?
| In the story | The real idea |
|---|---|
The API key typed directly into main.py | Hardcoded secret: a password, key, or token written straight into source code instead of kept separately |
| quietpatch0x's polite GitHub issue | Responsible disclosure: reporting a security problem quietly to whoever can fix it, instead of exploiting or publicising it |
| "Deleting the line doesn't remove it from history" | Git keeps every past version of a file; a secret committed once is considered exposed forever unless history itself is rewritten |
Moving the key into a .env file | Environment variables: a way to supply secrets to running code without ever writing them into the code itself |
The new .gitignore file | A list of files and patterns Git is told never to track, keeping sensitive files out of what gets uploaded in the first place |
| Bots scanning public repositories for key patterns | Secret scanning: automated tools, run by GitHub, providers, and independent researchers, that watch for exposed credentials at scale |
| The free-tier sending cap that limited the damage | A spending or usage limit is a safety net, not a plan; the real fix is never exposing the secret in the first place |
Try it yourself
Secret exposed, or safely handled?
Here are four lines you might find in a real project. Tap one to see whether it's a safe practice or a leaked-secret risk, and why.
Tap a line above to check it.
Maths corner
What a leaked key can actually cost
Say a leaked API key has no spending cap, and once found, an attacker's script fires 1,000 requests every second, each costing the account holder ₹0.15. That's 1,000 × ₹0.15 = ₹150 per second.
Your turn. At that rate, how much does one minute cost? One hour? And if quietpatch0x's report had instead taken 3 hours to arrive, with the key already found and used by someone less polite, roughly how much could have been lost?
Answer: ₹150 × 60 = ₹9,000 per minute, and ₹9,000 × 60 = ₹5,40,000 per hour. Over 3 unlucky hours, that's roughly ₹16,20,000, entirely from one line of code and no spending cap, which is exactly why CampusConnect's free-tier cap, and a fast report, mattered so much.
Try it on a computer · optional
The fix: reading secrets from the environment
# the risky way, a secret baked right into the code API_KEY = "sk_live_7hT9k2xPq..." # the safer way, read from the environment instead import os API_KEY = os.environ.get("API_KEY") if not API_KEY: raise ValueError("Set API_KEY as an environment variable before running this.")
The second version never contains the real key anywhere in the code, so pushing it to a public repository leaks nothing. The key lives only in a local .env file, which .gitignore keeps out of every commit.
Run this in any free online Python editor. Try removing the os.environ.get(...) line and hardcoding a fake key instead, then imagine that file being pushed to a public repository, which version would you rather have written?
Security tip
Five habits for every project repository
Add a .gitignore file before writing a single line of code, not after. Never type a real key, password, or token directly into a source file, use environment variables or a secrets manager from day one. Treat any secret that's ever been committed, even briefly, as compromised, and rotate it rather than simply deleting the line. Set spending or usage caps wherever a service allows it. And if someone reports a leaked secret to you, however the message arrives, say thank you before you question it, politely reported problems deserve a fast fix, not suspicion.
Did you know?
Fun facts
Myth or fact?
"If I delete the line with the secret in my next commit, it's gone."
MythA new commit only adds a new snapshot. Every earlier snapshot, including the one with the exposed secret, still exists in the project's full history and remains visible to anyone who looks. The only real fix is rotating the secret itself, treating anything ever committed as burned, regardless of how quickly it was "removed" afterward.
Try this · no computer needed
Spot the secret
You need: paper and a pen, and at least one other person.
- One person writes out eight short, made-up lines of "code" on paper, ordinary variable assignments, with two of them secretly containing a fake password or key written in plain text.
- The other person has sixty seconds to read all eight lines and circle the ones they think are unsafe to push to a public repository.
- Reveal the answers, then discuss: what made the risky lines stand out, or not stand out, at a glance?
- Swap roles with a new set of eight lines, then discuss: how might a tool catch what a quick human read misses?
Careers corner
Application security (AppSec) engineer
An AppSec engineer works with developers before code ever reaches production, reviewing it for exactly these kinds of mistakes, hardcoded secrets, unsafe handling of user data, missing permission checks, and building automated tools that catch them early. It's a career that sits between software development and security, equally comfortable reading code and explaining risk.
Useful to learn: at least one programming language well, secure coding patterns, how version control systems like Git actually work, and the patience to explain a fix clearly to a developer under deadline pressure.
Quiz time
How well did you learn?
Think and discuss
No wrong answers here
- Naina's first instinct was to suspect quietpatch0x's message was itself a scam. What made it different from the scam messages in earlier chapters, once she looked closer?
- Rehan pushed the code half-asleep at 1 a.m. How much of this chapter's mistake was really about security knowledge, and how much was about deadline pressure and tiredness?
- Why might a company reward someone for reporting a security flaw instead of punishing them for finding it?
- If you found a real exposed password in someone else's public project tomorrow, what would you do first?
Be curious
Ask a teacher, parent or engineer
Word bank
New words from this chapter
Coming up in Chapter 4
Rehan wants to be the next quietpatch0x. A classmate turns that curiosity into a bet, find a real bug first, and the line between ethical hacking and a very real legal problem turns out to be thinner, and closer, than Rehan expected.
For teachers and parents: this chapter fits two 40-minute periods. Period 1: read Parts 1 to 7 aloud (15 min), explore the "secret exposed or safely handled" interactive together (10 min), then the Maths corner (10 min). Period 2: "Spot the problems in this code" discussion, the "spot the secret" activity, and the quiz. The key ideas: secrets belong in environment variables, never directly in code; Git history keeps every past version, so a deleted line is not a removed secret; responsible disclosure is how security researchers report problems ethically; and a usage cap is a safety net, not a substitute for not leaking the secret at all. The Python corner is optional and uses only the concept of environment variables, no actual exploitation. All chapter illustrations are AI-generated scene art (pending for this draft); the code panel and secret-picker are built by hand.