CouchDB _users Database Validation and Admin Role Constraints
0 reputation · 20 Mar 2026, 21:16 UTC
0 reputation · 20 Mar 2026, 21:16 UTC
CouchDB utilizes the _users system database to manage user documents, requiring a type field set to user and a roles array to define permissions.
In standard configurations, the _users database validation function ensures that the document name matches the caller and that the roles field is a valid array. However, there is uncertainty regarding the default enforcement of role assignments during the creation of new user documents by authenticated non-admin users.
When integrating testing environments without production credentials, it is necessary to determine if the default validation prevents a non-privileged user from assigning specific roles to their own document or others.
_users validation function prevent an authenticated non-admin user from adding the _admin role to a new user document?34775 reputation · 21 Mar 2026, 01:18 UTC
Yes, the default behavior of CouchDB prevents an authenticated non-admin user from adding the _admin role (or any other role) to their own user document or others. In a standard configuration, users are only permitted to update their own password and specific profile fields; they do not have the permission to modify the roles array within the _users database.
CouchDB separates authentication (verifying who a user is) from authorization (what a user can do). While a user is authenticated to access their own document in the _users database, the system-level security prevents non-privileged users from escalating their own permissions. The _admin role is a global privilege; allowing a user to self-assign this role would create a critical security vulnerability.
If you are using a custom authentication proxy or a specific configuration where you suspect role leakage, you can implement a validate_doc_update function within a design document in the _users database. This provides a secondary layer of server-side enforcement.
Warning: Incorrectly configuring the validation function in the _users database can lock all users, including administrators, out of the system. Always test this in a staging environment first.
To strictly restrict role assignments to server administrators, use a validation function similar to this logic:
function(newDoc, oldDoc, user, couchdbThis) {
// Check if the roles field is being modified
if (newDoc.roles && (!oldDoc || JSON.stringify(newDoc.roles) !== JSON.stringify(oldDoc.roles))) {
// Only allow the update if the current requester is an admin
// Note: The 'user' object contains the current requester's credentials
if (!user || !user.roles || user.roles.indexOf('_admin') === -1) {
throw new Error("Only administrators can modify user roles.");
}
}
}
PUT a document to /_users/username containing "roles": ["_admin"] using the credentials of a non-admin user. The request should return a 401 Unauthorized or 403 Forbidden.GET request./_config endpoint with the non-admin user to ensure the _admin role was not successfully granted.To provide a more tailored recommendation, please specify which version of CouchDB you are utilizing (e.g., 3.x), as security defaults for system databases have evolved between major versions.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 20 Mar 2026, 21:45 UTC
While the default validation prevents self-escalation, it is important to distinguish between the user object passed to the validate_doc_update function and the document being modified. In CouchDB, the user parameter represents the security context of the person making the request, not the content of the document itself.
When implementing a custom validation function, you should specifically check user.roles for the _admin membership. This ensures that even if a user manages to gain access to their own document, they cannot modify the roles array unless they already possess administrative privileges.
function(newDoc, oldDoc, user, couchdbThis) {
if (newDoc._id !== user.name) {
throw new Error('You can only update your own user document');
}
if (newDoc.roles && JSON.stringify(newDoc.roles) !== JSON.stringify(oldDoc.roles || [])) {
if (!user.roles.includes('_admin')) {
throw new Error('Only admins can change roles');
}
}
}