Five Checkboxes and One Lock
The role editor offers five separate controls over receiving stock. One of them decides anything. The other four can be granted or withheld all afternoon and the system will behave identically — which is a worse outcome than having only one control, because it looks like you have five.
The short version
If you have ever configured a role by reading the checkbox labels and trusting them, go and check what each one actually governs. A permission that is offered, granted, withheld and audited — and read by nothing — is not a small cosmetic problem. It is a control you believe you have.
Open the role editor in almost any operations system and you will find a block of permissions for receiving stock. View. Create. Approve. Adjust. Reject. Five checkboxes, five verbs, and the obvious reading: whoever holds them can do those five things, and whoever does not, cannot.
That reading is how separation of duties gets configured in practice. The storekeeper books goods in; somebody else approves. You express it by granting the first person create and withholding approve. It takes ten seconds and it is the single most common internal control in stock handling.
We audited our own role editor against our own code on 26 August 2026, and in that block of five, exactly one permission is read by the software.
What each checkbox actually does
The distinction that matters is between a permission being declared and a permission being enforced. Declared means it appears in the list that builds the role editor — it can be granted, withheld, saved, exported and reported on. Enforced means some piece of code asks whether the person holding the request has it, and refuses if they do not.
All five are declared. Here is the enforcement.
The receiving permissions, and whether anything consults them
| Permission | In the role editor | Consulted by the code | Governs a reachable screen |
|---|---|---|---|
| View a receipt | Yes | Yes | Yes |
| Create a receipt | Yes | Yes | No |
| Approve a receipt | Yes | No | No |
| Adjust a receipt | Yes | No | No |
| Reject a receipt | Yes | No | No |
Built and maintained Configurable by you, not maintained by us Not built
The middle row is the one worth pausing on, and it is the reason this was not caught by reading the permission list alone. The create permission is consulted — by a piece of the application that no address reaches. It guards a door that was never built into a wall.
So what stops an unauthorised approval?
Something does, and this is the part that keeps the finding honest. Receiving stock produces a stock adjustment, and approving a stock adjustment requires a permission. That permission is real, it is enforced on every approval path, and without it nobody approves anything.
It is simply not the one on the checkbox you clicked. It is the general adjustment approval permission — the one that also covers write-offs, damages, count corrections and every other movement the adjustment mechanism carries.
The control is not missing. The control is coarser than the screen that configures it, and the screen does not say so.
Read that consequence slowly, because it runs in the direction people do not expect. An administrator who wants a supervisor to approve goods receipts, and only goods receipts, ticks the approve-receipt box and stops. That does nothing at all — the supervisor still cannot approve. So the administrator grants the general adjustment approval instead, and now the supervisor can approve every kind of stock adjustment in the business, including writing stock off.
The intended grant was narrow. The available grant is wide. The editor implied the narrow one existed.
How a permission ends up like this
Not through carelessness, in our case, and probably not in yours either. A permission list is written when a module is designed, and it describes the module as it was drawn. The module then gets built, and one screen turns out to be better served by an existing mechanism than by a new one — receiving stock is a kind of adjustment, so it goes through the adjustment machinery and inherits the adjustment permissions.
That is a good engineering decision. It produces one approval path instead of two, which is one place for a rule to live instead of two places for it to drift apart. What it also produces is a set of permission names that describe the design rather than the build, sitting in a config file that nothing forces to agree with the code.
That last figure is the one that made this worth publishing rather than just fixing. It is not a receiving problem. The same audit found the same shape in the ledger, in sales, in role administration and in the audit log itself — twenty-nine declared permissions that no code reads, spread across nine modules.
Why this is safe to write down
We publish absences and we do not publish bypasses — a control somebody can get around is a thing an insider can use, and it gets fixed before it gets described. Nothing on this page is a way through a lock. Approving a receipt still requires a real permission that is really checked. What is described here is the opposite problem: a grant you believe is narrow is broad, so the risk runs towards over-permissioning, and the fix is in your hands the moment you know.
The general lesson, which is not about us
Every system with a role editor has this failure mode available to it, because every system with a role editor keeps its permission names in one place and its permission checks in another. Nothing in a typical framework makes those two agree. A name can be deleted from the code and left in the list; a name can be invented for the list and never reach the code. Neither produces an error, a log line or a visible symptom.
And the symptom you would expect — somebody doing a thing they should not — does not occur either, because the missing check makes the permission inert, not permissive. Nobody gains access. The access simply is not partitioned the way the screen says it is.
So it survives audits. An auditor asked to confirm that approval is segregated will look at the role, see approve unticked for the storekeeper, and tick their own box. The evidence is a screenshot of a decision nothing carried out.
-
Pick the control you most rely on
Not all of them — the one you would name first if a bank asked how stock write-offs are governed. That is where the cost of being wrong is highest and the check is cheapest.
-
Grant a test account everything except that one permission
A real login, in your own workspace, with the exact role you believe is safe. This is the whole method and it takes a few minutes.
-
Try to do the thing
If you are refused, the permission is enforced and you have evidence. If you succeed, the checkbox is decorative and you have just learned something no documentation would have told you.
-
Then try it the other way round
Grant only that permission and nothing else, and see whether the screen opens. A permission can be inert and the screen can be governed by a different, broader grant — which is the case here and is the more dangerous half.
Four questions for any vendor with a permission list
Is every permission in your role editor checked somewhere in the code?
What you will hear
Almost always yes, said immediately and in good faith.
How to read it
Nobody is lying. Nobody has usually measured it either, because measuring it means comparing a config file against every route and controller. Ask how they know, and listen for whether the answer is a test or a belief.
If I withhold this specific permission, what exactly stops working?
What you will hear
A description of the screen it protects.
How to read it
The useful follow-up is "show me". A permission whose effect can be demonstrated in a live session is enforced; one that can only be described is not yet evidence of anything.
Can I approve one kind of stock movement without being able to approve all of them?
What you will hear
Often yes, because the names in the list suggest yes.
How to read it
This is the question that finds the coarseness. The honest answer for us today is no — one approval grant covers every adjustment type, and we say so below rather than letting the checkbox labels imply otherwise.
Does anything in your build fail when a permission stops being used?
What you will hear
Rarely.
How to read it
This is the only durable fix, and it is worth more than any assurance about the current state. A list checked by hand is correct on the day it is checked.
Two things, and the second one is the one that lasts
The first stops this being wrong today. The second stops it being wrong again, which is the part worth paying for.
Per-movement approval grants
Approval permissions that separate a goods receipt from an issue and both from a write-off, so a supervisor can be given the one you meant without being given the ability to write stock off. This is the control the role editor already implies exists, made real.
A build check that compares the list against the code
A test that fails when a permission is offered in the role editor and consulted by nothing, and fails again when a route is gated on a permission the editor never offers. Both directions matter — the second is how a permission becomes ungrantable rather than merely inert.
A permission map you can read
A screen showing, for each permission, which screens and actions it governs. This is what makes an access review possible at all: today the honest answer to "what does this grant let them do" is that somebody has to go and read the code.
How it works: you describe what you need governed, we return a written scope, timeline and cost, and once agreed it is built into your environment and maintained as part of the product. If a regulator or a lender has asked you to evidence segregation of duties, that is the moment to raise this rather than after the request arrives.
Talk to us about access controlWhat AWRA OpsHub does today
- Approval of a stock adjustment requires a permission, enforced on every approval path — the web screens and the API alike, with no path that skips it.
- A second, senior grant above a configurable value threshold, and separately a rule that the approver cannot be the person who raised the adjustment. That separation of duties is not overridable by any grant.
- Around 250 permissions across 25 groups, editable per role, with the role editor and the plan layer reading one shared definition.
- An audit log of role and permission changes, so a grant that was widened is answerable after the fact.
More we can add to your workspace
- Approval grants that separate one movement type from another. One permission covers approving every kind of stock adjustment today, so a receipt approver is also a write-off approver.
- A build check that fails when a declared permission is consulted by nothing. Twenty-nine are in that state across the product, which is how this page came to exist.
- A map of which screens each permission governs, readable without going to the code.
- Time-bound permission grants, so a temporary approval right lapses on a stated day rather than on somebody remembering.
Where we point you to a specialist
- We will not present a permission as enforced because it is present in a list. The list and the code are two artefacts and only one of them decides anything, and where they disagree we would rather publish the disagreement than describe the list.
- Deciding which duties your business must separate is your call and, in a regulated sector, your auditor's. We build the partition you specify; we do not tell you which one satisfies your obligations.
- Where a control can be worked around rather than simply waiting to be built, we fix it before writing about it. A control on the roadmap tells you what to plan around; a bypassable one tells the wrong reader what to do.
Per-movement approval grants and the build check that keeps the permission list honest are both scoped work we can quote on.
Check one permission this week
Not the whole list — one. The control you would name first if somebody asked how stock write-offs are governed in your business. Grant a test account everything except that permission and try to do the thing. Ten minutes, and you will either have evidence or a finding.
Talk to us about your access controls