Platform admin routes that can write tenant data without logging are invisible to both the tenant and to compliance auditors. CWE-778 (Insufficient Logging) and OWASP A09 (Security Logging and Monitoring Failures) both apply; SOC 2 CC6.8 explicitly requires that privileged actions be logged with who, what, and when. The practical risk is that an insider threat — a rogue admin or compromised admin account — can modify or delete tenant data with no forensic trail, making incident response and regulatory defense impossible.
Low because admin routes are access-controlled, but an unlogged admin write operation eliminates any forensic trail for insider-threat scenarios or compliance audits.
Wrap every admin write route in a logging function that captures the actor, action, affected tenant, and resource before returning:
// src/lib/admin-audit.ts
async function adminUpdateUser(
adminId: string,
targetUserId: string,
changes: Partial<User>
) {
const updated = await db.user.update({
where: { id: targetUserId },
data: changes
})
await db.adminAuditLog.create({
data: {
adminUserId: adminId,
action: 'user.update',
targetUserId,
targetOrganizationId: updated.organizationId,
changes: JSON.stringify(changes), // redact sensitive fields like passwords
timestamp: new Date()
}
})
return updated
}
In src/app/api/admin/, require this wrapper pattern for every POST, PATCH, PUT, and DELETE handler. Read-only GET handlers do not require the same trail but should still be access-controlled.
ID: saas-multi-tenancy.tenant-management.admin-view-no-modify-without-trail
Severity: low
What to look for: Examine admin or super-admin routes — routes accessible only to platform administrators (not tenant admins). Check whether admin actions that modify tenant data (editing records, overriding settings, impersonating users, deleting data on behalf of a tenant) are logged with sufficient detail to reconstruct what was done and by whom. Look for admin route handlers that perform write operations without any audit log creation.
Pass criteria: Enumerate all admin endpoints. At least 100% of admin write operations against tenant data must create an audit log entry that includes: the admin's user ID, the action taken, the tenant affected, the resource modified, and a timestamp. Admin view-only access (read operations) does not require the same logging, but read access to sensitive tenant data should at minimum be access-controlled.
Fail criteria: Admin write operations on tenant data execute without creating any audit trail. An admin can modify a tenant's data and there is no record of the action in any log or table.
Skip (N/A) when: No admin or super-admin routes are detected. Signal: no admin route group, no admin role check in any route handler, no "impersonate" or "act as tenant" functionality.
Detail on fail: Example: "POST /api/admin/users/[id] can update any user's data but writes no audit log entry. No record is kept of admin modifications to tenant user accounts."
Remediation: Wrap admin write operations with audit logging:
async function adminUpdateUser(adminId: string, targetUserId: string, changes: Partial<User>) {
const updated = await db.user.update({
where: { id: targetUserId },
data: changes
})
// Always log admin mutations
await db.adminAuditLog.create({
data: {
adminUserId: adminId,
action: 'user.update',
targetUserId,
targetOrganizationId: updated.organizationId,
changes: JSON.stringify(changes), // consider redacting sensitive fields
timestamp: new Date()
}
})
return updated
}