Vulnerability 4: Missing Authentication (CWE-306)
OWASP A07:2021 — Identification and Authentication Failures
Severity: High — Complete Unauthorized Access
What Is the Vulnerability?
The isValidToken() method exists in the vulnerable codebase — it's fully implemented. But it is never called by any of the six file operation methods. Every method (upload, download, delete, rename, list, search) receives a token parameter and silently ignores it.
Any client with any token — even a completely fabricated one — can read, write, and delete any file.
This Is a Subtle Bug
This isn't a missing feature. It's an incomplete integration — the developer wrote the validation method but forgot to call it from the operation methods. The code compiles, the method exists, and a code review might see isValidToken() in the class and assume it's being used.
Vulnerable Code
File: vulnerable/src/server/ReplicaNode.java
// VULNERABILITY 4: isValidToken() IS IMPLEMENTED but NEVER CALLED.
// The token parameter is received by every method but silently ignored.
// Result: any caller can perform any operation without authentication.
// ---- The method that exists but is never called: ----
@SuppressWarnings("unused")
private boolean isValidToken(String token) {
return sessions.containsKey(token);
}
// ---- All six methods IGNORE the token parameter: ----
@Override
public String upload(String token, String filename, byte[] data) throws RemoteException {
// VULNERABILITY 4: Token is NEVER VALIDATED.
// An attacker with FAKE_TOKEN="not-a-real-token" can still upload files.
saveFile(filename, data);
multicastOperation("UPLOAD", filename);
return "File uploaded successfully";
}
@Override
public byte[] download(String token, String filename) throws RemoteException {
// VULNERABILITY 4: Token ignored. Download works without auth.
return readFile(filename);
}
@Override
public String delete(String token, String filename) throws RemoteException {
// VULNERABILITY 4: Token ignored. Delete works without auth.
deleteFileLocally(filename);
multicastOperation("DELETE", filename);
return "File deleted";
}
// ... list(), search(), rename() all have the same problem
Attack Demo
Attacker4_UnauthorizedAccess
cd vulnerable
# (nodes must be running)
java -cp out attacker.Attacker4_UnauthorizedAccess
The attacker uses a completely fabricated token:
// Attacker4_UnauthorizedAccess.java
public class Attacker4_UnauthorizedAccess {
public static void main(String[] args) {
FileSystemService service = /* connect to vulnerable server */;
String FAKE_TOKEN = "i-am-an-attacker-and-this-token-is-not-real";
// ALL of these succeed — the server never validates the token:
// List files without login
String files = service.listFiles(FAKE_TOKEN);
System.out.println("Files: " + files); // Lists all files! No auth needed!
// Upload a malicious file
service.upload(FAKE_TOKEN, "attacker_file.txt", "evil content".getBytes());
// Download any file
byte[] data = service.download(FAKE_TOKEN, "secret_doc.txt");
System.out.println("Downloaded: " + new String(data));
// Delete a file
service.delete(FAKE_TOKEN, "important_config.txt");
// Rename a file
service.rename(FAKE_TOKEN, "report.pdf", "report.pdf.deleted");
}
}
Every operation succeeds despite using a token that was never issued by the AuthService.
The Fix
File: secured/src/server/ReplicaNode.java
Step 1 — RequireAuth Helper
// FIX 4: Called at the start of EVERY client-facing method.
// Throws RemoteException if the token is invalid.
private void requireAuth(String token) throws RemoteException {
if (token == null || token.isEmpty()) {
throw new RemoteException("UNAUTHORIZED: No session token provided");
}
if (!isValidToken(token)) {
throw new RemoteException("UNAUTHORIZED: Invalid or expired session token");
}
}
Step 2 — Call requireAuth on EVERY Operation
@Override
public String upload(String token, String filename, byte[] data) throws RemoteException {
requireAuth(token); // ← ADDED: Validate BEFORE doing anything
saveFile(filename, data);
multicastOperation("UPLOAD", filename);
return "File uploaded successfully";
}
@Override
public byte[] download(String token, String filename) throws RemoteException {
requireAuth(token); // ← ADDED
return readFile(filename);
}
@Override
public String delete(String token, String filename) throws RemoteException {
requireAuth(token); // ← ADDED
deleteFileLocally(filename);
multicastOperation("DELETE", filename);
return "File deleted";
}
// Same fix applied to: list(), search(), rename()
Step 3 — Session Token Management
In the secured version, the token is a UUID generated at login and stored in a ConcurrentHashMap:
// AuthService stores: token → username
private final ConcurrentHashMap<String, String> tokens = new ConcurrentHashMap<>();
// At login:
String token = UUID.randomUUID().toString();
tokens.put(token, username);
return token; // Sent to client over mTLS
// Validation:
boolean validateToken(String token) {
return tokens.containsKey(token);
}
Why This Vulnerability Is Dangerous
| Property | Impact |
|---|---|
| Exploitability | Trivial — no credentials needed at all |
| Impact | Complete — attacker can read, write, delete any file |
| Prerequisites | Network access to the RMI port |
| Anonymity | Perfect — attacker leaves no login trace |
| Persistence | Attacker can plant files, delete backups, corrupt data |
Real-world parallel: This is like a bank vault where the lock is installed but the door is left propped open. The security mechanism exists but isn't engaged.
Why This Bug Happens
This is a classic incomplete implementation — a security feature that was planned, partially implemented, but never integrated. The fix is trivial (call requireAuth() at the top of every method), but the bug can survive code reviews because the validation method's presence creates the illusion of security.
Next: → Replay Attack Prevention