My app was hacked: what to do now

Contain first: take the app offline or block access, and rotate every password, token and key. Then preserve the logs, find out how they got in and rebuild from clean code.

Updated 7 min read

Learning objectives

After reading this article you will be able to:

  • Contain a breach in the right order, without destroying evidence
  • Diagnose the most common causes of a hacked app
  • Rebuild the app, restore data and prevent another breach
On this page

A breach rarely shows up as a clear error message. The sign is usually indirect: the site shows a page you never made, CPU sits at 100% with no traffic, the AI API bill comes in high, an admin account nobody created appears, or the database disappears and a ransom note takes its place.

In that moment, the urge is to delete whatever looks wrong and move on. That is the most common mistake: you destroy the clues about how the attacker got in and leave the door open for them to come back. The order below follows the incident response guidance in NIST SP 800-61: contain first, then investigate, recover and prevent.

first hourDetectfiles and CPU1Containtake offline androtate secrets2Preserve logsbefore deletinganything3Investigatehow they got in4Rebuildfresh deploy,earlier snapshot5Monitorlogs and CPU6
Contain and preserve the evidence first; clean up only after finding the cause, rebuilding from the repository.

How do you know the app was really hacked?#

Look for these signs, from most to least common in small apps:

  • Changed or new files that are not in your repository, such as scripts injected into the HTML or a .php file in a Node.js app.
  • High, constant CPU with no rise in visits. Cryptocurrency miners are the typical payload after a breach.
  • Strange accounts and charges: new admin users, heavy usage on paid APIs, bulk emails sent through your provider.
  • Deleted or encrypted data, sometimes with a new table or collection holding a ransom demand.
  • Successful requests for sensitive files in your access logs, like this one (example):
text
203.0.113.7 - - [12/Oct/2026:03:14:07 +0000] "GET /.env HTTP/1.1" 200 1532 "-" "Mozilla/5.0"

The 200 in that line means the server handed out your .env file with all of your secrets. Check right now whether your site exposes files that should never be public. The expected answer is 404 or 403:

bash
for path in .env .git/config; do
  printf '%s -> ' "$path"
  curl -s -o /dev/null -w "%{http_code}\n" "https://www.yoursite.com/$path"
done

If you have access logs in a file, search for requests that succeeded:

bash
grep -E '"GET /\.(env|git)' access.log | grep -E '" 200 '

What should you do in the first hour?#

Follow this order. Do not start with cleanup.

  1. Contain. Stop the app or block public access. An app offline for an hour costs less than an active attacker for another hour.
  2. Preserve evidence. Before deleting anything, download the logs and a copy of the files on the server. Without that material, you will not find the cause.
  3. Rotate every secret. Database passwords, bot tokens, API keys, session and JWT signing keys, email and storage credentials. Treat everything the app could read as compromised, including its environment variables.
  4. Lock down the surrounding accounts. Change the password and turn on two-factor authentication on GitHub, your domain registrar and your hosting dashboard. End open sessions.
  5. Invalidate user sessions. Rotating the session or JWT signing key logs everyone out, including the attacker.

For bot tokens and API keys, the detailed steps are in leaked your bot token and API key exposed on GitHub.

How do attackers usually get in?#

These are the most common causes in small apps, from most to least frequent.

Leaked secrets#

A .env committed to a public repository, served by the site itself or included in a shared ZIP. Check your Git history and run the curl test above. A leaked secret can explain the whole breach: whoever had the database password needed no flaw in your code.

A database exposed with no password#

A database open to the internet without authentication gets broken into quickly by bots that scan addresses. The Redis administration docs warn that, by default, Redis requires no authentication and listens on all network interfaces. MongoDB binds only to localhost by default, according to its security docs, but many people switch it to 0.0.0.0 to "make it work". Check that your database requires a password and only accepts connections from your app.

A vulnerable dependency#

An outdated library with a known flaw. Run your language's audit and compare the dates the flaws were published with the date of the breach:

bash
npm audit --audit-level=high
pip-audit -r requirements.txt

npm audit asks the registry for known vulnerabilities in your dependencies and exits with an error when it finds something at the given level. pip-audit does the same for Python.

A flaw in your code#

SQL injection from concatenating text into a query, an upload that accepts any extension and saves to a public folder, a system command built from user input, an admin route with no permission check. Look in your access logs for routes that got strange requests shortly before the first signs.

A weak password or a compromised account#

An admin panel with a short password and no attempt limit, or the GitHub account of someone on your team. If the attacker made commits or deploys, your Git history and deploy logs show when.

To compare what is running with what is in your repository, use a copy downloaded from the server:

bash
git diff --no-index --stat ./my-repo/src ./server-copy/src

Any file that appears only in the server copy deserves attention.

How do you clean up and get back online?#

Do not try to "fix" the hacked server file by file. Rebuild:

  1. Fix the cause in the code: update the dependency, close the database, remove the exposed file, fix the query.
  2. Deploy fresh from the repository instead of reusing the files that were on the server.
  3. Use the new secrets, never the old ones.
  4. Restore the data from a copy made before the breach, if the database was changed. See how to back up a database to set up a routine that makes this possible.
  5. Monitor closely over the next few days: access logs, CPU usage and third-party service accounts.

Do you have to notify anyone?#

If users' personal data may have leaked, probably yes. In the EU, the GDPR requires the controller to notify the supervisory authority within 72 hours of becoming aware of a breach, unless it is unlikely to result in a risk to people. Other countries and states have their own breach notification laws, and the risk assessment is yours to make. If in doubt, get legal advice.

Tell your users directly too: explain what happened, which data was affected and what they should do, such as changing their password on other services where they reused it.

How do you prevent another breach?#

  • Secrets out of the code and out of any folder the site serves.
  • A database reachable only by the app, always with a password and TLS.
  • Dependencies audited on every deploy.
  • Two-factor authentication on every account that can deploy.
  • A WAF in front of the app to block known attack patterns; see what a WAF is.
  • Tested copies of your data, stored off the server.

The deploy security checklist brings these items together with code examples.

How to do this on Square Cloud#

On Square Cloud, the order in this article maps to steps in the dashboard. To preserve evidence, copy the logs from the dashboard or with the CLI's app logs command (logs from before a restart stay visible) and take a manual snapshot of the application before you touch any file; manual snapshots are available on every plan. The browser file manager shows the application's disk, which helps you find what isn't in your repository. To rotate secrets, edit the environment variables in the dashboard, the API, the CLI or the VS Code extension; the change applies on the next restart, without a rebuild.

When you rebuild, deploy from your repository into a new application rather than over the old one: the disk persists across deploys and a commit only overwrites the files in the ZIP, so whatever the attacker left would still be there. For data, databases get a daily automatic snapshot on every plan that includes databases, and applications from the Pro plan. Each daily snapshot is kept for 7 days, so pick one from before the breach. A database snapshot restores into the same database, another of the same engine or a new database, and can also be downloaded as a .zip.

Applications run in isolated containers without root access, and one cannot read another's variables or files, even in the same account. Every plan includes a WAF and L3/L4/L7 DDoS protection. Those layers limit the damage, but they do not fix a flaw in your code or a leaked secret: incident response is still yours. See how environment variables and snapshots work.

Infrastructure

L3/L4/L7 DDoS mitigation and a WAF on every plan

Learn more

FAQs

Is it enough to delete the strange files and restart?

No. The attacker may have left another way in, and the credentials they saw are still valid. Rotate every secret and rebuild the app from the code in your repository.

Do I have to tell anyone if user data leaked?

Probably. Under the GDPR, a personal data breach that poses a risk to people must be reported to the supervisory authority within 72 hours of becoming aware of it. Other jurisdictions have their own rules, so get legal advice if in doubt.

How do I know whether the attack is still going on?

After rotating secrets, watch your access logs, CPU usage and third-party service accounts. New access with rotated credentials means the way in is still open.

Does restoring an old copy fix it?

It fixes the data, if the copy is from before the breach. But if the flaw that allowed the attack is still in the code, the app can be hacked again. Fix the cause before going back online.

Next articleSecurity checklist for deploying a bot, site or APIA security checklist before you deploy a bot, site or API: secrets in environment variables, dependencies, HTTPS, headers, least privilege and logs.

More in Security

See all 10 articles