Skip to main content
All insights
Security10 min readAugust 6, 2026

Five Ordinary Intranet Features That Leak Information

The short answer

Internal software often leaks through ordinary responses rather than dramatic breaches. A hidden field can still be present in a list API, a document count can reveal a restricted file, and a room conflict can expose who is meeting whom. The reliable defence is to define what must not leave each query, serializer, count and export before designing the visible interface.

By Timothy Indarsingh, Founder & CEO, Firelinkx

This is part of the engineering series behind our intranet platform case study. An employee directory, a noticeboard, a document library, a helpdesk and a room booker are the features most likely to be described as standard. None is difficult to demonstrate. Each becomes difficult when the requirement is not what a user can see, but what every other user must never learn.

The leaks in this article are not passwords printed on a screen. They are quieter: a field returned to the browser and hidden with CSS, a count that admits a protected record exists, an audit event that copies the sensitive value it is meant to protect, or a conflict message that volunteers the purpose of somebody else's meeting. In a regulated group where two legal entities must remain distinct, these are design failures, not cosmetic rough edges.

1. Directory: hiding a column is not withholding a field

The directory has tiered profile data. Some fields are suitable for any authenticated employee, while others belong to managers, HR or IT. The tempting implementation is to fetch a complete employee object and let the component decide which fields to render. That solves presentation and leaves disclosure untouched. Anyone who can inspect the response still receives the data, and a list endpoint turns the mistake into a bulk export.

We exclude restricted fields in the query and serializer that produce the response. Remote-support and internal-system identifiers cannot appear in list results because the list projection does not contain them. The detail route can add an authorised tier deliberately, but the common path starts with the smallest public employee shape rather than a full record that must be trimmed perfectly every time.

Even the org chart is bounded. It returns the subject, a limited manager chain and direct reports around that person. Traversal is capped, protected against cycles, restricted to the legal entity and limited to public-tier fields. A read-only organisational convenience still needs controls against malformed hierarchy data and cross-entity disclosure.

The practical rule

If a caller must not see a field, the field must not be present in the response. Rendering is not an authorization boundary.

2. Announcements: calculate the audience from the organisation as it exists now

Announcements can target legal entities, territories, offices and departments. Each dimension is an allow-list, the dimensions combine, and an empty list means the announcement is unrestricted on that dimension. We evaluate those rules when the announcement is read. We do not generate a permanent recipient row for every employee at publication time.

Materialising recipients looks efficient until somebody transfers offices or changes department. The announcement then carries a frozen picture of an org chart that no longer exists. Read-time evaluation keeps the audience aligned with current organisational facts and avoids a second recipient dataset that can drift, leak or require its own correction process.

One storage choice is deliberately unfashionable. The audience lists use delimiter-bracketed text rather than JSON arrays because the fast test database cannot exercise the framework's JSON containment lookup reliably. The text representation is less elegant, but the most security-relevant rule in the domain runs in every test environment. We chose broad testability over a prettier column type and recorded the trade-off.

Announcement HTML is sanitised with an allow-list at the write boundary. Sanitising only on render assumes every future renderer will remember to do it. Cleaning before storage means dangerous markup never becomes a reusable database value. Review still found a more human bug: an author could be excluded by the audience they had just defined and lose access to their own announcement. The correction made authorship an explicit visibility claim rather than an accidental exception.

3. Documents: the count can reveal the file

The knowledge base filters documents by lifecycle state, organisational scope and a protected flag. Those filters apply to lists and category counts. If a category says it contains twelve documents but the caller can open only eleven, the interface has disclosed that another document exists. Its category, approximate arrival and restricted status may be enough to reveal something meaningful even when its title is never returned.

A restricted document's existence can be sensitive, so concealment must include aggregates. This is a general lesson for dashboards: totals, facets, search suggestions and empty-state wording are all outputs. Authorization that guards only the record detail page protects less than developers often think.

Document versions are new rows linked by supersession. The predecessor changes state in the same transaction, preserving which version was available at any earlier date. Major policy revisions produce a new acknowledgement obligation by construction, while minor revisions can carry existing acknowledgements forward. Earlier acknowledgements are never rewritten to point at text the employee did not read.

Acknowledgement reporting returns counts rather than a rounded completion percentage. A percentage can make a nearly complete rollout feel finished while concealing the people still outstanding. A numerator and denominator keep the remainder visible and allow the authorised owner to follow up without exposing individual acknowledgement data to everyone who can see the policy.

Files are reached through short-lived signed URLs with server-generated storage keys and a malware-scan gate. Read activity belongs in a separate access trail rather than the append-only legal audit log: downloads are high-volume operational telemetry, while access changes and acknowledgements are durable governance evidence. Mixing the two makes both harder to use.

4. Helpdesk: sensitive context needs a different data path

A support ticket can contain information the requester may see, internal notes they may not see, and restricted context available only to a smaller support group. We store the restricted context separately so the ordinary list serializer cannot reach it. This is stronger than remembering a field exclusion in every endpoint because the common query does not join the sensitive table.

Audit events for restricted context record which fields were accessed, not the values. Otherwise the audit log becomes a second copy of the secrets it is meant to govern. The system can prove that a support agent opened a protected identifier without placing that identifier into a longer-lived, more widely reviewed log.

Ticket visibility is built as a union of legitimate claims—own ticket, assigned work, department reach and entity authority—then intersected with the legal-entity boundary. The union makes the helpdesk usable across normal collaboration paths. The final intersection is absolute. Internal notes stay internal, and priority remains a triage decision rather than a value the requester can set, which prevents every request from becoming urgent by default.

Concurrent state changes use a precondition that names the expected state. A generic version check can say that the record changed; a state-aware rejection can say that another agent already accepted the ticket. Both prevent the stale write, but only one gives the user a useful next step. Security and usability meet in the quality of the refusal.

5. Booking: a conflict response is an information channel

A reservation claims a set of resources. A room and its linked projector may need to be available together, so conflict detection covers the complete set in one decision. A free room does not make the request valid when its required equipment is already committed. Approval repeats the conflict check because availability at submission is not a promise that the world will remain unchanged until an approver acts.

When a collision exists, the response identifies the unavailable resource and time window. It does not name the other organiser, meeting title or purpose. The naive helpful message can tell an employee who is meeting, where and why. A booking system has no reason to disclose those details to explain that a slot is unavailable.

Recurring reservations become individual rows, each checked independently, and the response lists occurrences that could not be booked. A recurrence rule evaluated lazily can hide a clash until week six. Blackout creation locks the affected resource set and atomically cancels overlapping pending and approved bookings, returning their identifiers so people can be notified. Times are stored in UTC and presented in the resource's territory, because the room does not move when the viewer travels.

The pre-release review found two authorization defects in this domain, including an approval check whose empty input produced the opposite of the intended result. Both were corrected before release. The full mechanics and the review discipline that found them belong in Permission Bugs Are Silent; repeating them here would obscure this article's point, which is how many ordinary outputs can disclose information even when the central permission check is correct.

Reporting: omit instead of redact

Export is a separate authority from view. Reading a few dozen records through an interface and taking thousands away in a file are different capabilities. Rows are restricted to the exporter's scope, sensitive columns are omitted rather than blanked, and the audit event records exactly which columns left the platform.

Blanking is weaker than omission. It announces the field exists, preserves its position for downstream processing and encourages somebody to ask why it is empty. A schema built for the authorised export is clearer than a full schema populated with redactions. When data leaves, the system should know both which records and which attributes left with it.

How to review negative requirements

  • Inspect network responses and serializers, not only what the component renders.
  • Test counts, facets, search suggestions, error messages and conflict payloads as disclosure surfaces.
  • Ask whether logs and audit events duplicate the protected values they describe.
  • Exercise empty collections, expired grants, moved employees and approval-time state changes.
  • Treat bulk export as a distinct capability and record the columns released.

We write the negative case at the same level as the positive contract. If an endpoint says what an authorised manager receives, its tests also say what an ordinary employee cannot receive. If a category count is scoped, the count and list are tested from the same caller context. If an export is allowed, the test examines its headers as well as its row count. This turns absence into something observable enough to regress.

The review must also follow data beyond the first response. A protected value omitted from the API can reappear in a log, notification, cache key or generated filename. A restricted row filtered from search can still influence a total. Negative requirements are end-to-end statements about what leaves a boundary, not annotations attached to a single screen.

The takeaway

Negative requirements rarely impress in a demonstration. Nobody applauds the identifier absent from a list response or the meeting title missing from a conflict. Those omissions are nevertheless the substance of a safe intranet. Start each domain by listing what an unauthorised caller must not learn, then carry that list through queries, counts, messages, exports and logs. Blocking the detail page is only the beginning.

Want your security gaps checked?

Firelinkx helps Guyanese businesses get this right. Get a clear scope, timeline, and price, or just ask a question. We respond within 24 hours on business days.

WhatsApp Us