Ravindra BagaleCourses & study guides मराठी Track your progress

30. Cloud and AWS Security

30.4 Protecting Data: S3, Encryption and Secrets

S3 exposure is the classic cloud leak. Defences:

  • Turn on S3 Block Public Access at the account level (S3 console, Block Public Access settings for this account). This overrides mistakes on individual buckets.
  • Serve public files through CloudFront with Origin Access Control instead of making the bucket public.
  • Use bucket policies that allow only your app role; enable versioning so deleted or ransomed files can be restored.
aws s3api get-public-access-block --bucket reels-media-pune
aws s3api put-public-access-block --bucket reels-media-pune \
  --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
aws s3api put-bucket-versioning --bucket reels-media-pune --versioning-configuration Status=Enabled

Encryption. S3 encrypts new objects by default (SSE-S3). For more control use KMS keys (SSE-KMS): you decide who may use the key, and every use is logged in CloudTrail. Tick "Encryption" when creating RDS and EBS volumes – it cannot be switched on later without a snapshot copy.

Secrets. Database passwords and API keys belong in AWS Secrets Manager or SSM Parameter Store (SecureString), not in config.php committed to Git.

aws ssm put-parameter --name /reels/db/password --type SecureString --value 'Str0ng#Pass'
aws ssm get-parameter --name /reels/db/password --with-decryption --query Parameter.Value --output text

The EC2 role then needs only ssm:GetParameter on that one parameter.

Ravindra Bagale's Tip

The reason for making a bucket "public" is always "the images weren't showing". The right fix for that is CloudFront + OAC, not a public bucket. And once you turn on account-level Block Public Access, future mistakes are stopped automatically too.

Lab

Enable account-level Block Public Access. Move the database password of your reels app from config.php into SSM Parameter Store as a SecureString, give the EC2 role permission to read only that parameter, and update the PHP code to fetch it with the AWS SDK.

Real incident: Meta – stolen employee GitHub login used to take code and personal data (Oct 2026)

1. What happened

On 13 October 2026, Meta said an outside group got into some of its GitHub repositories using one employee's stolen credentials. Meta detected the intrusion a few weeks earlier. About 99% of what was taken was business data – software code for some Meta products. The other 1% was personal data that had been put into the repositories by mistake, against company policy. Meta is notifying about 1,500 people, most of them Meta employees in the US, and is offering them credit and dark-web monitoring. Meta cut off the attackers' access, brought in GitHub and law enforcement, rotated the secrets found in the repositories, and is adding scans to catch personal data uploaded to GitHub by mistake. Meta says no Meta product had a vulnerability and its internal systems were not breached. It has not said what types of personal data were involved.

2. How the hack happened (public reporting only – high-level)

  1. An attacker gets hold of one employee's GitHub login (Meta has not said exactly how it was stolen).
  2. The attacker signs in as that employee – to GitHub it looks like a normal user.
  3. The attacker reads and copies repositories that employee could access.
  4. Inside the code are secrets (keys, tokens) and some personal data that someone had committed by mistake – so a code leak also becomes a data leak.
  5. Meta detects the access, cuts it off and rotates every secret in those repositories so stolen keys stop working.

3. How to stop it / defend (this lesson: Protecting Data, S3, Encryption and Secrets)

  • Strong login for code platforms. Turn on MFA for GitHub, and prefer phishing-resistant security keys or passkeys over SMS codes.
  • Short-lived tokens. Use fine-grained tokens with an expiry date, and SSO for the organisation, so a stolen token works only for a short time.
  • Never put secrets in code. Keep passwords and keys in SSM Parameter Store or Secrets Manager (like the Lab above), not in config.php or Git.
  • Turn on secret scanning and push protection. GitHub can block a push that contains a key before it is saved.
  • No real personal data in repositories. Use fake test data. Real customer or employee data belongs in an encrypted, access-controlled store.
  • Watch the audit log. Alert on unusual clones, many downloads, or logins from new places.

4. How to take care so it won't happen again (checklist)

  • [ ] MFA is required for every member of your GitHub organisation.
  • [ ] Personal access tokens are fine-grained and expire within 90 days or less.
  • [ ] Secret scanning and push protection are switched on for all repositories.
  • [ ] Run a scan of your old commits for keys and personal data, and rotate anything found.
  • [ ] Each person can reach only the repositories they need.
  • [ ] When someone leaves, their access and tokens are removed the same day.
  • [ ] India students: personal data in code also falls under the DPDP Act – keep it out of Git, and report major incidents to CERT-In within the required time (see Ch.34).

Source: SecurityWeek, "Meta Says Hackers Took Code, Personal Data of 1,500 in GitHub Breach", 13 October 2026; Cybernews, "Meta GitHub breach exposes data of 1,500 people", October 2026.

Check if you're safe: Password Strength Checker

Real incident: Gheist – stolen GitHub tokens used to print private repository secrets into GitHub Actions logs (Oct 2026)

1. What happened

In this lesson you learned one rule: secrets (passwords, API keys, cloud keys) must live in a safe store, not in code. This real case shows the next step. Even when secrets are stored the right way, anyone who can write to the repository can make a pipeline read them. A GitHub token is like a password that lets a program use your GitHub account. A GitHub Actions workflow is a small file in the repository that tells GitHub to run jobs (build, test, deploy) by itself.

  • On 25 October 2026, the cloud security company Wiz published research on a campaign it calls Gheist. Wiz has tracked it since 15 September 2026.
  • The attackers used stolen GitHub tokens. For every repository a token could reach, their tool added a small workflow that printed the repository's secrets into the job log.
  • Wiz recovered more than 13,500 planted branches from more than 850 compromised accounts, from personal projects to the private repositories of enterprise organizations.
  • Since 28 July 2026, GitHub holds suspicious workflow runs in public repositories until a collaborator approves them. Every public Gheist run Wiz checked was stuck there, so it never ran. But this hold does not cover private repositories or GitHub Enterprise Server. There, the runs completed.
  • In some enterprise organizations, Wiz saw the tool clone private repositories first. Hours later, cloud credentials from the same organization were used to list AWS Secrets Manager secrets. Wiz does not say where those credentials came from.
  • Wiz says the stolen tokens came from sources such as infostealer logs (data stolen by malware from people's computers) and tokens exposed in earlier supply-chain attacks. As of 24 October the campaign was still running, and about two-thirds of the accounts involved were no longer available on GitHub.

2. How the hack happened (public reporting only – high-level)

  1. The attacker got stolen GitHub tokens that could write to repositories.
  2. For each repository, the tool made a new branch with a name like ci-sync- plus six random characters.
  3. On that branch it added one workflow file named sync-check, with the commit message ci: sync config. The commit looked like it came from the token's owner.
  4. A push starts a workflow by itself. So the job ran at once and printed every secret it could read. The values were encoded, so GitHub's automatic hiding of secrets in logs did not recognise them.
  5. One version ran the job once for each deployment environment, so environment secrets (often production keys) were printed too.
  6. The tool downloaded the log through GitHub's own API and deleted the run seconds later. The secrets left through GitHub itself, so there was no attacker server to block.
  7. From about 19 October, one version also tried to search self-hosted runner machines for more keys. Wiz calls that job buggy and reports no successful run.

3. How to stop it / defend (this lesson: protecting secrets)

Why: a secret is only as safe as the list of people and jobs that can read it. On GitHub, anyone with write access to a repository can use every secret in it. So a stolen token with write access is enough.

Controls you can use:

  1. Put production secrets in a protected environment. In the repository go to Settings, then Environments, then create production, then turn on Required reviewers. A job cannot read that environment's secrets until a reviewer approves it.
  2. Use OIDC instead of stored cloud keys. OIDC lets a workflow get a short-lived AWS login, so no long-lived AWS key sits in GitHub. In the AWS role trust policy, allow only your protected branch or environment. Example condition value: repo:YOUR-ORG/YOUR-REPO:environment:production. A random new branch then cannot get the role.
  3. Keep the real secret in AWS Secrets Manager or SSM Parameter Store, like this lesson's lab. Give the pipeline role read access to only the one secret it needs.
  4. Use short-lived, fine-grained tokens or GitHub Apps instead of old personal access tokens. Give each token only the repositories it needs, and set an expiry date.
  5. Run self-hosted runners as short-lived machines, without Docker socket access and without open access to the cloud metadata service.

Example: check your own repository for planted branches. Run these steps one by one.

  1. Open a terminal inside your own cloned repository.
  2. Run git ls-remote --heads origin 'ci-sync-*'
  3. Output when you are safe: nothing. The command prints an empty result and returns to the prompt.
  4. Output when there is a problem: a line like 9f2c… refs/heads/ci-sync-a1b2c3. It means a branch with that name exists on GitHub.
  5. What it means: if you find one, do not run or approve it. Rotate every secret the repository could use, then revoke the token that pushed it. Deleting the branch or the run does not undo the leak.

4. How to take care so it won't happen again (checklist)

  • [ ] Production secrets sit in an environment with Required reviewers.
  • [ ] Pipelines sign in to AWS with OIDC, and the trust policy allows only protected branches or environments.
  • [ ] No long-lived AWS keys are stored as GitHub secrets.
  • [ ] Every GitHub token is fine-grained, has an expiry date, and reaches only the repositories it needs.
  • [ ] Every month, look in the audit log for workflow runs deleted within a minute and for unknown new branches.
  • [ ] If a token leaks: rotate every secret it could reach, revoke the token, and scan the owner's computer for infostealer malware.
  • [ ] Self-hosted runners are short-lived and have no Docker socket.

Source: Wiz Blog, "Gheist: Attempted Scaled Abuse of Stolen GitHub Tokens Stumbles" (Rami McCarthy, Hila Ramati), 25 October 2026; The Hacker News, "Gheist Uses Stolen GitHub Tokens to Steal Private Repository Secrets via Actions Logs", 26 October 2026.

Check if you're safe: Password Strength Checker

Real incident: Chainalysis – offensive agentic AI intrusion exposed customer profile data (Oct–Nov 2026)

1. What happened

In this lesson you learnt that “protecting data” means knowing which fields an attacker can reach even when the crown-jewel investigation content stays locked.

  • On about 30–31 October 2026, crypto-compliance firm Chainalysis disclosed a security incident. It updated the notice around 2 November 2026.
  • An external actor used what Chainalysis called “offensive agentic techniques” to reach internal systems and tools.
  • Accessed data was described as non-sensitive customer account / profile fields: user IDs, full names, email addresses, and organization role labels.
  • Chainalysis said it found no evidence of access to investigation content, transaction or query results, clear-text passwords, MFA secrets, or session tokens.
  • Customers were notified; users were told to enable MFA and watch for suspicious password-reset or authentication requests.

2. How the hack happened (public reporting only – high-level)

  1. An outside actor automated parts of the intrusion with agent-style offensive tooling.
  2. That path reached some internal tools that could read customer profile records.
  3. Profile fields (names, emails, roles, IDs) were exposed; deeper investigation data was not, per the company.
  4. Chainalysis contained the access, assessed scope per customer org, and published updates.
  5. Customers were asked to harden login (MFA) and treat unexpected reset mails as suspect.

3. How to stop it / defend (this lesson: protecting data)

Why: even “just email + name + role” is enough for targeted phishing against your staff and your customers.

Controls you can use:

  1. Separate profile stores from investigation vaults with different credentials and networks.
  2. Turn on MFA account-wide and check admin MFA coverage (Example 1).
  3. Alert on password-reset spikes after any vendor breach mail (Example 2).
  4. Publish a status page customers can trust when rumors start (Example 3).
  5. Least privilege on internal tools that can dump user directories – agents love wide API tokens.
  6. Log and review agent / automation identities the same way you review human admins.

Example 1: sanity-check cloud MFA posture on an account you own.

  1. Run aws iam get-account-summary 2>/dev/null | head -n 20
  2. Output: like "AccountMFAEnabled": 1,\n"Users": 42.
  3. What it means: root/account MFA is on. Still enforce MFA on every human and automation user.

Example 2: watch password-reset lines in your app auth log.

  1. Run grep -iE 'password.?reset|mfa|login' /var/log/app/auth.log 2>/dev/null | tail -n 5
  2. Output: like 2026-10-31T09:12:01Z WARN password_reset requested for user=alex@example.com ip=198.51.100.9.
  3. What it means: a reset from a strange IP right after a breach headline is a call to the user, not a quiet ignore.

Example 3: read your own status API (or skip if you have none).

  1. Run curl -s https://status.example.com/api/v2/summary.json 2>/dev/null | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("status",{}).get("description","n/a"))' 2>/dev/null || echo status-check-skipped
  2. Output: like All Systems Operational.
  3. What it means: customers need one trusted place for “what was accessed” updates.

4. How to take care so it won't happen again (checklist)

  • [ ] Profile PII and investigation data sit in different trust zones.
  • [ ] MFA required for every customer and every internal admin.
  • [ ] Password-reset and new-device alerts are on.
  • [ ] Automation / agent service accounts are inventoried and short-lived.
  • [ ] Customer notice template names exactly which fields were / were not touched.
  • [ ] Post-incident: rotate tokens the agent path could have seen.

Source: Chainalysis blog, "Security Incident Information" (October 30 disclosure, updated November 2, 2026); BleepingComputer, The Hacker News, SecurityWeek and The Block coverage of the same notice.

Ravindra Bagale's Tip

“Only names and emails” is still phishing fuel. After an agentic intrusion, force MFA, watch password-reset spikes, and say clearly which fields were and were not touched.

Check if you're safe: Password Strength Checker