My sftp.json file got exposed. What should I do?
This isn't a map of your server — it's the keys. An sftp.json (the config the popular VS Code SFTP extension writes to .vscode/sftp.json) stores your host, port, username and password in plain text. If it was public, anyone who read it can log straight into your server right now. Act in minutes, not days.
First: don't panic — but treat the server as already compromised.
Unlike a config that merely describes a service, this file hands over a working login. The single most important thing is speed: change that password before you do anything else, then work the rest of the list. If the username is root, assume whoever found it had full control of the box.
// the 60-second version
- Change the leaked password immediately — it works right now.
- Remove the file from the web root and scrub it from git history.
- Read the SSH/auth logs — did anyone log in with those creds?
- Hunt for persistence; if root logged in, plan a clean rebuild.
01Understand what just leaked
The VS Code "SFTP" extension keeps its connection details in a project file at .vscode/sftp.json. It looks like this:
{
"protocol": "sftp",
"host": "203.0.113.42",
"port": 23022,
"username": "root",
"password": "••••••••••••", // plain text!
"remotePath": "/var/www/html/archive/legal"
}
Every field is a gift to whoever found it:
- host + port — exactly where to connect, including a non-standard SSH port (it doesn't slow anyone down).
- username — the account to use. If it's
root, a successful login is total control of the server. - password — in clear text. There's nothing to crack; they just paste it in.
- remotePath — where your site's files live on disk, so they know exactly where to drop a web shell or read your data.
This is the highest-severity exposure of the three guides here. A leaked .env or .git gives an attacker secrets to use; a leaked sftp.json often gives them an interactive root shell. Treat the box as compromised until your logs prove otherwise.
02Change the password — right now
This is the one step that can't wait. The credentials in the file are live, so your first move is to make them worthless. Log in to the server (console, or SSH if you still trust the session) and change the affected account's password:
# for the leaked account (e.g. root) passwd # changing another user's password as root passwd <username>
- If the leaked user was
root, change root's password and every other account on the box — assume the attacker may have added or read others. - Prefer to retire passwords entirely — switch to SSH key authentication and disable password login (step 6). A key can't be copy-pasted out of a JSON file.
- If you suspect someone is in there right now, consider temporarily firewalling off SSH (or detaching the box from the network) while you investigate.
03Close the exposure — stop serving the file and scrub it
A sftp.json almost always leaks one of two ways: the whole .vscode/ folder got deployed into your public web root, or it was committed to a repository. Fix both.
Stop it being served
Remove the file (and ideally the whole .vscode/ directory) from anything web-facing, then deny it at the web-server level. For Nginx:
location ~ /\.(vscode|git|env) { deny all; return 404; }
Re-request the URL from outside your network and confirm it returns 404, not the JSON.
Scrub it from git
If it was committed, the password is in your history even after you delete the file. Rotating (steps 2 & 4) is what actually protects you, but clean up too:
# stop tracking it everywhere, forever echo ".vscode/sftp.json" >> .gitignore # purge it from all of history git filter-repo --path .vscode/sftp.json --invert-paths
04Rotate everything the login could reach
Because someone may have had a shell on the server, a single password change isn't enough — anything reachable from that box should be considered exposed. Work through:
- Other credentials stored on the server — application
.envfiles, database passwords, API keys, cloud tokens, TLS private keys. Rotate them at the source. - SSH keys — regenerate host and user keys, and review every
~/.ssh/authorized_keysfor entries you didn't add. - Anything under the
remotePath— the attacker knew exactly where your files were. Rotate secrets stored there and check the files themselves (next step). - Reused passwords — if that password was used anywhere else, change it there too.
FTP/SFTP passwords like this often pre-date the leak by months. If the same value protected anything else, treat all of it as burned and rotate widely.
05Read the logs — did anyone log in?
This is the question that decides everything else. Check the server's authentication logs for logins using the leaked account, especially from IPs you don't recognise:
# Debian/Ubuntu: /var/log/auth.log • RHEL/CentOS: /var/log/secure # every accepted login — watch for root and unfamiliar IPs grep "Accepted" /var/log/auth.log # recent sessions, including still-active ones last -aw | head who # brute-force noise (and whether any of it finally worked) grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn
Cross-reference with your web access logs to see when sftp.json was first fetched and by whom — that timestamp is the start of your exposure window:
grep "sftp.json" /var/log/nginx/access.log | grep " 200 "
06Assume compromise — hunt for persistence
If you found logins you can't explain — or simply can't rule them out — work on the assumption an attacker was inside, and look for the footholds they leave behind:
- New SSH keys in any
authorized_keysfile, and new or unexpected user accounts (/etc/passwd,lastlog). - Scheduled tasks — unfamiliar entries in crontabs,
systemdtimers, or/etc/cron.*. - Web shells & tampered files under your
remotePath(/var/www/…) — look for recently modified PHP/scripts you didn't deploy. - Altered logs — gaps or truncation suggest cleanup; lean on any off-box/SIEM copies.
If a root login succeeded, you can't fully trust the machine again. The only clean answer is to rebuild from a known-good image and restore data after scanning it. Patching what you can see leaves whatever you can't.
07Make sure it can't happen again
- Never store a plaintext password in
sftp.json. Use key-based auth instead — point the extension at aprivateKeyPath(or use an SSH agent). A key file isn't something that leaks in one careless deploy. - Keep
.vscode/out of git and out of the web root. Add it to.gitignore, and deploy build artifacts only — never your editor folder. - Lock down SSH — set
PermitRootLogin noandPasswordAuthentication noinsshd_config, and connect as a normal user withsudo. - Deny dotfiles by default at the web server (step 3) so a stray
.vscode,.gitor.envis never served. - Add fail2ban and a firewall, and alert on successful logins from new IPs so the next surprise comes from your monitoring, not a stranger.
Was this guide useful?
These playbooks are free to read and share. If a heads-up ever saved you a bad week, you can say thanks — or jump into the other guides.