Field Guard
Field Guard is for Drupal architects and security teams that need selected fields to fail closed—even for administrators and even when JSON:API or Views asks about a field without loading an entity. Wilkes & Liberty maintains the GPL-licensed module for Drupal 10.6+, 11.3+, and Drupal 12. Policy lives in exported configuration and names permissions the site already owns.
Why it exists
A sensitive field can leak information without ever being rendered. JSON:API and Views perform definition-level checks to decide whether a field may be filtered or sorted, sometimes with no entity in scope. Returning a neutral access result can leave the filter or sort surface available, allowing a caller to infer a hidden date, status, classification, or other value through repeated queries.
A second trap is Drupal's administrator behavior. hasPermission() returns true for every permission on user 1 and roles marked administrative. A module that intends to deny access when a permission is absent may silently exempt the most powerful accounts before it ever returns a forbidden result.
Who should use it, and when
- Drupal security architects protecting fields whose existence, ordering, or filter behavior is sensitive.
- API teams exposing JSON:API or Views where rendered-value access alone does not close inference paths.
- Compliance operators who want grants to appear as explicit, reviewable role configuration rather than administrator inheritance.
- Distribution maintainers who need the same field policy imported consistently across environments.
Use Field Guard for a small, deliberate map of sensitive fields. Do not use it as a universal replacement for Drupal's entity, bundle, workflow, or business-rule access systems.
Where it enforces policy
Field Guard implements Drupal's field-access hook. For a configured entity type, bundle, field, and operation, it returns AccessResult::forbidden() unless a regular, non-administrator role explicitly contains the named permission. Drupal combines field-access results so a forbidden verdict cannot be overridden by another module, user 1, or an administrative role.
When no entity is provided—the definition-level path used for filtering and sorting—the module denies the guarded field for everyone. That removes the inference surface, with an intentional tradeoff: even an otherwise authorized user cannot filter or sort that field when Drupal offers no entity context.
Configuration model
protected:
profile:
compliance_record:
field_evidence_date:
view: 'view compliance evidence'
edit: 'record compliance evidence'
The hierarchy is entity type → bundle → field → operation → permission. Only view and edit are valid operations. Omitted operations are open, empty permission strings are treated as unset, and the module ships with an empty map—installation alone changes nothing.
The closed configuration schema rejects misspelled operation keys instead of accepting a policy that does nothing. Access results carry the settings cache dependency, so changing the map invalidates earlier decisions rather than leaving a protected field readable from stale cache.
Why explicit role grants matter
For value-level checks, Field Guard loads the account's roles, skips roles marked administrative, and inspects the remaining role configuration directly. A grant therefore appears as a line in configuration that can be reviewed, deployed, and reverted. This creates separation of duty without inventing a second permission system: the module defines no permissions and never grants access.
Honest boundaries
Field Guard governs Drupal's field-access API. Direct SQL, Drush, and custom PHP that reads $entity->get() without calling field access can still see the value. The module does not log reads; its protected-field map exposes a seam for an audit consumer such as Audit Chain.
Protection is exact-match. Unlisted entity types, bundles, fields, and operations remain open. Do not guard workflow fields such as moderation_state or status on edit: Drupal checks field edit access against the stored value during an API patch, while transition rules need validation that can inspect the incoming value.
The definition-level denial makes a guarded field unfilterable and unsortable for everyone. If authorized filtering is a requirement, redesign the query surface rather than weakening the no-context decision.
Install, configure, and test
Requires PHP 8.1+ and Drupal core Field and User. The same configuration model applies across the supported Drupal versions; the declared compatibility ranges reflect tested core API support rather than different feature sets.
composer require drupal/field_guard
drush en field_guard
# Add field_guard.settings.yml to configuration, then import normally.
drush config:import
The repository's kernel tests cover administrator/user-1 denial, definition-level JSON:API and Views behavior, configuration validation, and cacheability. The key test to inspect is NullItemsFailsClosedTest.
Project, source, issues, and related work
- Field Guard project page and releases on Drupal.org
- Source code and tests on GitHub
- Issue queue on Drupal.org
- Field Permissions, the broader UI-driven alternative
- Audit Chain for tamper-evident event records
Maintained by Jeremy Michael Cerda and Wilkes & Liberty under GPL-2.0-or-later. The checked source release for this page is 1.1.0.