Skip to main content

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

PropertyImpact
ExploitabilityTrivial — no credentials needed at all
ImpactComplete — attacker can read, write, delete any file
PrerequisitesNetwork access to the RMI port
AnonymityPerfect — attacker leaves no login trace
PersistenceAttacker 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