Pyssly

The robotsThe thief's own card

The thief's list

Every day, programs ask Pyssly for files we have never had: passwords, source code and backups. Here is the list, how many times they have asked, why a thief wants each file, and how to protect your own site.

A paper robot with an empty sack sneaks toward a filing cabinet.

Who is the thief?

The thief is usually not a person sitting there searching. It is a program that goes from site to site with the same list and asks for every file on it.

If a site answers with the file, the thief has the key without breaking anything open. Pyssly has none of these files, so the thief gets a pretend page and we count the request.

If you have a homepage, a website or a server: make sure these files cannot be downloaded. At the bottom you can see how to check.

Most wanted

This is how many times robots have asked Pyssly for the files.

Counting …

Passwords and keys

The biggest treasure: a single file with everything that unlocks the site.

How to protect yourself

  • Never put secrets in the folder the web server shows to the world. Read them from environment variables or a secrets service (secrets in Kubernetes, GitHub Actions or the cloud) instead.
  • Block all files and folders that start with a dot in the web server, except /.well-known/. How to do it is further down.
  • Never put a private key in the web folder, and keep your own login keys to yourself, protected with a passphrase.

Source code

The whole site's code, with every change that was ever made.

How to protect yourself

  • Never upload the .git folder. Build the site and send only the built result, or keep the folder out with a .dockerignore.
  • Block dot folders in the web server for extra protection.
  • If a password was ever in the code: change it. Deleting it in a new change is not enough, because it is still in the history.

Databases and backups

Copies that someone put on the server for a while and then forgot.

How to protect yourself

  • Keep backups outside the web folder, preferably on another machine.
  • Block .sql, .bak, .zip and the like in the web server.
  • Don't edit files directly on the server: editors leave copies like .swp and ~ behind.

WordPress

WordPress runs a big part of the web, so the thief always tries its doors, even on sites without WordPress, like Pyssly.

How to protect yourself

  • Update WordPress, themes and plugins, and remove plugins you don't use.
  • Turn on two-step login, and switch off xmlrpc.php if you don't need it.
  • WordPress also looks for wp-config.php one folder above its installation. Move it there only if that folder is not itself served on the web, and never leave copies of the file.

Database tools

Programs that let you manage the database from a web page.

How to protect yourself

  • Don't put database tools on the public site. Run them on your own computer and reach the database through an SSH tunnel or a VPN.
  • If they have to be there: lock them behind an extra login or a list of allowed addresses.

Debug pages

Pages that developers use to look inside a site while it runs. Great on your own computer, dangerous on the web.

How to protect yourself

  • Never run a site in debug mode on the web: APP_DEBUG=false, and no development setup in production.
  • Remove phpinfo files and test tools before the site goes live (composer install --no-dev).
  • Lock operations pages like Actuator and server-status to your own address or an internal network.

Old doors

Programs and pages that the server runs when someone asks for them.

How to protect yourself

  • Remove everything the server doesn't need to run: old scripts, test pages and folders like cgi-bin.
  • Change the factory password on routers and cameras, update them, and never show their settings pages to the internet.
  • Let only what should run be run: an uploaded file must never be able to run as code.

Shops and phishing sites

Two kinds of searching that are not a break-in right away, but close.

How to protect yourself

  • What a shop shows to everyone, everyone can read. Don't put anything secret in goods or product fields.
  • If you see a folder or file you don't recognize on your server, like lander/: someone may have broken in. Remove it, change all passwords and update everything.

Block them in the web server

The best protection is that the files are never on the server. The blocks here are an extra safety in case something ends up there anyway.

All of them leave /.well-known/ open, because it is needed for things like certificates. Try them on a test site first.

nginx First in the site's server block. nginx uses the first regex rule that matches, and a location ^~ (for example for /static/) skips them altogether, so put the same rules inside it too.
# First in the server block: nginx takes the first regex location that matches,
# and a location ^~ (such as /static/) skips them, so repeat these inside it.
# Dotfiles (.env, .git, .htaccess) at any depth, but not /.well-known/
location ~ /\.(?!well-known/) {
    return 404;
}
# Databases, backups and old copies
location ~* \.(sql|bak|old|orig|swp|zip|tar|gz|7z)$ {
    return 404;
}
Apache In the site's settings or in .htaccess (Apache 2.4).
# Dotfiles (.env, .git, .htaccess) at any depth, but not /.well-known/
RedirectMatch 404 "/\.(?!well-known/)"
# Databases, backups and old copies
<FilesMatch "\.(sql|bak|old|orig|swp|zip|tar|gz|7z)$">
    Require all denied
</FilesMatch>
Caddy In the site's block in the Caddyfile.
# Dotfiles (.env, .git, .htaccess) at any depth, but not /.well-known/
@hidden {
    path_regexp /\.
    not path_regexp ^/\.well-known/([^./][^/]*/?)*$
}
respond @hidden 404
# Databases, backups and old copies, /.well-known/ included
@copies path_regexp \.(sql|bak|old|orig|swp|zip|tar|gz|7z)$
respond @copies 404
.dockerignore Decides what goes into the image when it is built, in every folder. It does not cover files mounted in while the container runs, and it is no block in Traefik: the block belongs in the app or the web server.
**/.git
**/.env*
**/*.sql
**/*.bak
**/*.zip
**/id_*
**/*.tfvars

How to check

Five minutes in a terminal. Swap example.com for your own address.

Only check your own site. Looking for other people's files is exactly what the thief does.

  1. Ask for .env

    curl -sS -i https://example.com/.env

    Look at both the answer and what comes with it. 404 or 403 is good. If your settings come back, the file is public. (If the site answers 200 to everything, as many apps do, what comes back should be your normal page.)

  2. Ask for .git

    curl -sS -i https://example.com/.git/HEAD

    If you see a line like ref: refs/heads/main, the whole source code is out in the open. An error page or your normal page is good.

  3. Try under other folders

    curl -sS -i https://example.com/static/.env

    A block can be missed in folders that are served directly, like /static/ or /assets/. Try there, and try more files from the list, like a .sql or an old copy of a settings file. What counts is whether the content shows.

  4. Look in the log

    grep -E '\.env|\.git/|wp-login|phpinfo|\.sql' /var/log/nginx/access.log

    The requests come every day, so seeing them is nothing strange. A 200 in the log does not prove a leak, since many apps answer 200 with their normal page. If you see a 200 for .env or .git/HEAD, fetch the address as above and look at what comes back.

If a file got out

  • Remove the file and block the address.
  • Change every password and key that was in it: the database, the email, payment services and the cloud account. Assume the thief already has them.
  • Look in the log for who fetched the file, and whether anything has happened to the accounts since.

More about thieves and other kinds of robots in How the robots work.