Loading content...
Secure Copy Protocol (SCP) holds a unique position in the history of secure file transfer. Born alongside SSH in 1995, SCP was designed with a single, elegant goal: provide the familiar semantics of the Unix cp command while leveraging SSH's encryption. For over two decades, system administrators reached for scp as naturally as they reached for cp—the syntax was nearly identical, the mental model trivial.
Yet this simplicity came at a cost. SCP's design, inherited from Berkeley's rcp (remote copy) protocol from the 1980s, carried fundamental limitations that became increasingly problematic:
In April 2022, OpenSSH 9.0 formally deprecated SCP's legacy protocol, switching the scp command to use SFTP protocol internally by default. Understanding SCP remains valuable for historical context, legacy system integration, and appreciating why SFTP became the preferred solution.
By the end of this page, you will understand SCP's architectural design and its relationship to SSH, the SCP protocol mechanics including command structure and data flow, practical usage patterns and command-line syntax, the security vulnerabilities that led to deprecation, migration strategies from SCP to SFTP, and scenarios where SCP knowledge remains relevant.
SCP's architecture reflects its heritage as a secure replacement for BSD's rcp (remote copy) command, created in the era of trusted local networks and the .rhosts authentication model.
Historical Context: From rcp to scp
In the 1980s, BSD Unix introduced rcp for copying files between systems. Users configured .rhosts files specifying trusted hosts; commands like rcp server:/path/file ./local worked seamlessly—and completely without encryption. When SSH emerged in 1995, scp provided identical functionality over SSH's secure channel.
The Simplicity Principle:
SCP operates on a fundamentally different model than SFTP:
How SCP Uses SSH:
Unlike SFTP's subsystem model, SCP operates through SSH's remote command execution:
12345678910111213141516171819202122232425262728293031
SCP Connection Model vs SFTP: SFTP:┌──────────┐ ┌──────────────┐│ Client │ ─── SSH Channel ──────────→ │ sftp-server ││ │ (subsystem request) │ (subsystem) │└──────────┘ └──────────────┘ Binary SFTP protocol ←→ SCP:┌──────────┐ ┌──────────────┐│ scp │ ─── SSH Channel ──────────→ │ scp -t/-f ││ (client) │ (exec request) │ (remote scp) │└──────────┘ └──────────────┘ Stream data + text headers ←→ When you run: scp localfile user@server:/remote/path 1. Local scp establishes SSH connection to server2. SSH authenticates user3. Local scp requests remote execution of: "scp -t /remote/path" (-t = 'to' mode, receiving files)4. Remote scp runs in receive mode5. Local scp sends file data through SSH channel6. Remote scp writes to filesystem7. Both sides exit, connection closes For download: scp user@server:/remote/file ./local Remote runs "scp -f /remote/file" (-f = 'from' mode, sending files)The -t (to) and -f (from) flags are internal to SCP protocol negotiation. Users never type them directly. When you run 'scp file remote:path', your local scp automatically invokes 'scp -t path' on the remote. These flags signal which role each side plays in the transfer.
SCP uses a simple text-based protocol for metadata, with raw binary data transfer for file contents. Understanding this protocol reveals both its elegance and its vulnerabilities.
Protocol Message Types:
SCP defines a handful of control messages, all text-based with newline terminators:
| Prefix | Format | Direction | Purpose |
|---|---|---|---|
| C | Cmmmm size filename | Sender→Receiver | Announce file with permissions, size, name |
| D | Dmmmm 0 dirname | Sender→Receiver | Enter directory (recursive mode) |
| E | E | Sender→Receiver | Exit directory level |
| T | Tmtime 0 atime 0 | Sender→Receiver | Set modification and access times |
| (null) | \0 | Both | Acknowledgment (success) |
| (0x01) | \x01message | Receiver→Sender | Warning message |
| (0x02) | \x02message | Receiver→Sender | Fatal error, abort transfer |
File Transfer Sequence:
123456789101112131415161718192021222324252627
Upload: scp report.pdf user@server:/home/user/ Sender (local) Receiver (remote scp -t) │ │ │ [SSH connection established] │ │ [Remote exec: scp -t /home/user/] │ │ │ │ ←──────── \0 ───────────────── │ Ready acknowledgment │ │ │ ─── T1642345678 0 1642345600 0 ────→ │ Timestamps (optional with -p) │ │ │ ←──────── \0 ───────────────── │ Timestamp accepted │ │ │ ─── C0644 102400 report.pdf ───────→ │ File header: │ │ mode=0644, size=102400 bytes │ │ │ ←──────── \0 ───────────────── │ Ready to receive │ │ │ ─── [102400 bytes of file data] ─────→ │ Raw file content │ │ │ ─── \0 ──────────────────────────────→ │ Transfer complete │ │ │ ←──────── \0 ───────────────── │ File accepted │ │ │ [Connection closes] │The SCP protocol's trust model is fundamentally flawed. When you request files from a malicious server, the server controls what filenames and content it sends. An attacker-controlled server could send '.bashrc' when you requested 'report.txt', or include hidden files in directory transfers. The client trusts the server's file metadata without validation. This vulnerability class led to SCP's deprecation.
Despite deprecation, the scp command remains available in modern OpenSSH, now using SFTP protocol internally while maintaining familiar syntax. Understanding command usage helps both with legacy systems and the modern hybrid implementation.
Basic Syntax:
1234567891011121314151617181920212223242526272829303132333435363738
# Basic file upload (local to remote)scp localfile.txt user@remote:/path/to/destination/ # Basic file download (remote to local)scp user@remote:/path/to/file.txt ./local/directory/ # Copy with custom SSH portscp -P 2222 file.txt user@remote:/path/ # Recursive directory copyscp -r /local/directory user@remote:/remote/parent/ # Preserve file attributes (mode, times)scp -p file.txt user@remote:/path/ # Verbose output for debuggingscp -v file.txt user@remote:/path/ # Quiet mode (suppress progress meter)scp -q largefile.iso user@remote:/path/ # Limit bandwidth (in Kbit/s)scp -l 1000 hugefile.tar user@remote:/path/ # ~125KB/s # Use specific identity file (private key)scp -i ~/.ssh/deploy_key file.txt user@remote:/path/ # Enable compression (good for text, bad for already-compressed)scp -C logfile.txt user@remote:/path/ # Remote-to-remote copy (proxied through local machine)scp user1@server1:/file.txt user2@server2:/destination/ # Copy multiple filesscp file1.txt file2.txt user@remote:/path/ # Wildcard patterns (expands locally before transfer)scp *.log user@remote:/var/log/archive/Important Command Options:
| Option | Long Description | Common Use Case |
|---|---|---|
| -r | Recursively copy entire directories | Backing up directory trees |
| -p | Preserve modification times, access times, and modes | Maintaining file attributes |
| -P port | Connect to specified port on remote host | Non-standard SSH port |
| -i identity | Use specified identity file for authentication | Automated scripts with deploy keys |
| -C | Enable compression in SSH layer | Text files over slow links |
| -l limit | Limit bandwidth usage (Kbit/s) | Preventing network saturation |
| -q | Quiet mode, disable progress meter | Scripted transfers, logging |
| -v | Verbose mode for debugging | Troubleshooting connection issues |
| -3 | Copy between two remotes via local host | When remotes can't directly connect |
| -F config | Use specified SSH config file | Custom SSH configurations |
| -o option | Pass options directly to SSH | Any SSH option as ssh_config |
| -O | Use legacy SCP protocol (not SFTP) | Compatibility with old servers |
| -s | Use SFTP protocol internally | Default in OpenSSH 9.0+ |
Starting with OpenSSH 9.0, scp uses SFTP internally by default. If you encounter compatibility issues with old SFTP-unaware servers, use 'scp -O' to force the legacy SCP protocol. However, this should be a last resort—prefer upgrading the server if possible.
SCP's simplicity creates inherent limitations that SFTP was designed to address. Understanding these constraints explains why SFTP became the preferred protocol.
Fundamental Limitations:
Comparison: SCP Operations vs SFTP Capabilities:
| Operation | SCP Support | SFTP Support | Workaround for SCP |
|---|---|---|---|
| Upload file | ✓ Native | ✓ Native | — |
| Download file | ✓ Native | ✓ Native | — |
| List directory | ✗ None | ✓ READDIR | Separate ssh ls command |
| Resume transfer | ✗ None | ✓ OPEN + seek offset | Manual split/combine |
| Create directory | ✗ None | ✓ MKDIR | Separate ssh mkdir |
| Delete file | ✗ None | ✓ REMOVE | Separate ssh rm |
| Rename file | ✗ None | ✓ RENAME | Separate ssh mv |
| Check file exists | ✗ None | ✓ STAT | Separate ssh test -e |
| Get file size | ✗ None | ✓ STAT | Separate ssh stat |
| Modify permissions | ✗ None | ✓ SETSTAT | Separate ssh chmod |
| Symbolic links | Partial (copy target) | ✓ SYMLINK/READLINK | Copy with ssh readlink |
| Preserve times | ✓ -p flag | ✓ atime/mtime | — |
To compensate for SCP's limitations, administrators often created wrapper scripts combining scp with ssh commands for listing, permission changes, and directory creation. These scripts were fragile (shell quoting issues), inefficient (multiple connections), and security-risky (command injection). SFTP provides all these operations through a single, secure protocol.
The SCP protocol carries fundamental security vulnerabilities that cannot be fixed without breaking backward compatibility. These issues crystallized the decision to deprecate SCP in favor of SFTP.
The Trust Model Problem:
SCP's protocol places excessive trust in the remote server. When downloading files, the client trusts the server to send exactly what was requested. This trust is misplaced.
Attack Scenario:
123456789101112131415161718192021222324252627282930313233
User runs: scp untrusted@evil.server:data.csv ./ Expected behavior: Server sends: C0644 1000 data.csv [file contents] Result: ./data.csv created Actual attack: Server sends: C0644 1000 data.csv [file contents for data.csv] \0 C0644 5000 .bashrc <- MALICIOUS PAYLOAD [malicious bash config] \0 Result: ./data.csv AND ./.bashrc created! Next shell login executes attacker's code. Why this works:1. Client requests single file2. Server sends requested file (looks normal)3. Server sends additional unrequested file 4. Client lacks validation that transfer should be complete5. Malicious file written to predictable location Mitigation in patched versions:- Strict validation of received filenames against request- Rejection of additional files beyond request count- But: Protocol fundamentally trusts server too muchWhy SFTP Doesn't Have These Issues:
SFTP's design inherently protects against these attacks:
OpenSSH 8.0 (April 2019): Announced SCP protocol would be replaced with SFTP. OpenSSH 9.0 (April 2022): Default changed to SFTP protocol for scp command. The legacy protocol remains available via -O flag but is not recommended. Organizations should migration scripts and automation to use sftp or scp's new SFTP-based implementation.
Starting with OpenSSH 9.0, the scp command maintains its familiar syntax while using SFTP protocol internally. This hybrid approach preserves user experience while eliminating protocol vulnerabilities.
How It Works:
12345678910111213141516171819
Command: scp file.txt user@server:/path/ OpenSSH 8.x (Legacy Default):┌──────────────────────────────────────────────────────────────────┐│ scp → SSH connection → remote exec "scp -t /path/" → SCP protocol│└──────────────────────────────────────────────────────────────────┘ OpenSSH 9.x+ (SFTP Default):┌──────────────────────────────────────────────────────────────────┐│ scp → SSH connection → SFTP subsystem request → SFTP protocol │└──────────────────────────────────────────────────────────────────┘ Force legacy: scp -O file.txt user@server:/path/Force SFTP: scp -s file.txt user@server:/path/ Detection: scp -v file.txt user@server:/path/ 2>&1 | grep -i sftp # If using SFTP: "Transferring file ... via SFTP" # If using SCP: "Sending file ... via scp"Behavioral Differences:
While the command syntax remains identical, subtle differences emerge from the protocol change:
| Behavior | Legacy SCP (-O) | Modern SCP (SFTP) | Impact |
|---|---|---|---|
| Directory expansion | Remote shell globs | SFTP REALPATH/STAT | Different wildcard handling |
| Symlink handling | Follows links by default | Depends on server config | Potential behavior change |
| Error messages | Remote shell output | SFTP status codes | Different error text |
| File overwrite | Immediate overwrite | Can fail on permission | Stricter checking |
| Space in path | Requires quoting | Handled correctly | Fewer escaping issues |
| Performance | Single data stream | Multi-request capable | Potentially faster |
| Resume capability | Not available | Theoretically possible | Not exposed in scp CLI |
For scripts depending on scp, test with modern OpenSSH before upgrading in production. Watch for: wildcard expansion differences, symbolic link behavior, and error message parsing. When possible, migrate directly to sftp command for better compatibility and full SFTP feature access.
Server Compatibility:
The modern scp requires the remote server to have SFTP subsystem available. Most servers do, but exceptions exist:
If modern scp fails with SFTP errors, use 'scp -O' to fall back to legacy protocol. However, audit the server for security compliance—lacking SFTP often indicates outdated or non-standard SSH implementation.
Despite deprecation, understanding SCP serves practical purposes in specific scenarios.
Valid Use Cases for Legacy SCP:
When to Instead Use SFTP:
Use the scp command with its modern SFTP implementation for convenience. Use sftp directly for interactive sessions and advanced operations. Reserve 'scp -O' (legacy protocol) only for connecting to systems that cannot support SFTP. Always prefer upgrading legacy systems to modern SSH when feasible.
We've thoroughly examined SCP—its origins, protocol mechanics, limitations, vulnerabilities, and modern evolution. Let's consolidate the essential knowledge.
What's Next:
Having explored both SFTP and SCP protocols individually, the next page examines SSH integration—how these protocols leverage SSH's authentication, encryption, and configuration systems. You'll learn about SSH key management, tunneling, and the configuration options that affect secure file transfer in production environments.
You now understand SCP's complete story—from its origins as a secure rcp replacement through its deprecation and replacement by SFTP. This knowledge enables informed decisions about file transfer tools and helps maintain legacy systems requiring SCP compatibility.