Safeguard
Application Security•

ASVS 5.0 V8.1.1: Document Function and Data Access Rules

ASVS V8.1.1 requires written authorization rules for function level and data specific access. Build a permission matrix, keep it testable and tie it to code.

Safeguard Security Team
4 min read

ASVS 5.0 V8.1.1 (Level 1) requires authorization documentation that defines rules for restricting function level and data specific access, based on the consumer's permissions and on attributes of the resource. In plain words: write down who can do what, and to which records.

Why it matters

Broken access control stays at the top of most application risk lists, and a common root cause is simple. Nobody agreed on the rules, so each developer guessed. One endpoint checks the role, another checks ownership, a third checks nothing.

Documentation turns authorization into something you can review, test and change on purpose. It also gives testers an oracle: without a statement of what should happen, a response of 200 might be correct or might be a vulnerability.

How to implement it

Keep two parts together: a function matrix and a data rule list.

Function level matrix:

FunctionAnonymousMemberManagerAdmin
View own invoicesnoyesyesyes
Approve refundnonoyesyes
Manage usersnononoyes

Data specific rules, expressed in terms of resource attributes:

  • A member can read an invoice only if invoice.owner_id equals their user id.
  • A manager can read invoices where invoice.team_id is a team they manage.
  • Nobody can edit an invoice whose status is closed.
  • Admins can read all invoices but need a reason code logged.

Store this beside the code, ideally as machine readable policy so it is not a stale wiki page:

# authz/invoices.yaml
resource: invoice
actions:
  read:
    - role: member
      when: "resource.owner_id == subject.id"
    - role: manager
      when: "resource.team_id in subject.managed_teams"
    - role: admin
  approve_refund:
    - role: manager
      when: "resource.team_id in subject.managed_teams and resource.status == 'paid'"
    - role: admin
  edit:
    - role: member
      when: "resource.owner_id == subject.id and resource.status != 'closed'"

Then make the code follow the document. A single policy function that every handler calls keeps the rules in one place:

def can(subject, action, resource):
    for rule in POLICY[resource.kind][action]:
        if subject.role == rule["role"] and rule_condition_holds(rule, subject, resource):
            return True
    return False   # deny by default

Review the document in the same pull request as any change to permissions, and name an owner.

How to test it

Turn the matrix into automated tests. Each cell becomes a case: authenticate as the role, call the function, assert allow or deny. Each data rule becomes a positive and a negative case with two users.

import pytest

@pytest.mark.parametrize("role,expected", [("anonymous", 401), ("member", 403), ("manager", 200), ("admin", 200)])
def test_approve_refund(client, role, expected):
    r = client.post("/refunds/123/approve", headers=auth_for(role))
    assert r.status_code == expected

Also compare the document against the routes list. Any route that is not in the matrix is a documentation gap or a missing control.

Common mistakes

  • A permission list that names roles but says nothing about records.
  • Documentation that lives in a slide deck and was never updated.
  • Rules written as "managers can see their team" without defining how the team relation is evaluated.
  • No mention of default behavior. State that anything not allowed is denied.
  • Skipping service to service callers, which are consumers too.

Try it yourself

Pick one resource type. In ten minutes, write its read, edit and delete rules in the format above. Then ask a colleague to find an endpoint that handles it, and check whether the code matches. The gaps you find are your first backlog.

Quick check

Does the document need to be machine readable?

No. Readable and current is the requirement. Machine readable policy makes it easier to test and keep current.

Who counts as a consumer?

Any caller: users, service accounts, API clients and other applications.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.