Finding recommendations
Recommendations tell the client how to fix or mitigate the finding. They should be concrete enough that a developer or administrator knows what to change, without repeating controls the client already has in place. Prefer direct verbs that name the action and, when helpful, a short reason: plain language, short sentences, and general control terms rather than a patch specification.
See also Report writing, Finding descriptions, and Finding summaries.
Goal
A good recommendation:
- Addresses the general root cause we identified in the description.
- Names the control pattern to implement (e.g. object-level authorization, session binding) rather than re-stating endpoint paths, parameters, or comparison logic from the description.
- Sounds natural: plain words and short sentences, not stiff compliance phrasing.
- Is written as bullet points with full sentences.
- Uses a direct verb for the main action (e.g. "Set …", "Remove …", "Validate …") or "We recommend …" followed by the action (e.g. "We recommend setting …"). Do not use "you should …".
- Is tailored to the client's stack, architecture, and constraints.
- Skips controls that are already implemented during our testing.
- Notes pros and cons when a fix is not straightforward or may not fit the client.
Quick rules of thumb
- Use direct verbs. Start with the action the client should take (see Report writing). "Set the
HttpOnlyattribute on session cookies to prevent JavaScript from reading the cookie" is clearer than "You should enable cookie security." "We recommend setting theHttpOnlyattribute …" is also fine when it reads more naturally. - Fix the root cause. Prefer correcting the flawed design or configuration over generic hardening advice.
- Name the control pattern. Use correct security terminology (e.g. object-level authorization, session binding, authorize users on every request). Save endpoint paths, parameter names, and step-by-step implementation logic for the description.
- Sound natural. Write as you would in a code review: "check that the logged-in user may change this account" rather than "derive the authenticated user from the server-side session" or "verify the authenticated user is permitted to modify the requested resource."
- One bullet, one action. Each point should stand on its own as a complete sentence.
- Skip redundant advice. If
HttpOnlyis already set on session cookies, do not recommend it again. - Acknowledge trade-offs. When a fix has downsides or depends on business decisions, say so briefly.
Example (good recommendations)
For a session cookie missing the HttpOnly flag:
- Set the
HttpOnlyattribute on session cookies to prevent JavaScript from reading the cookie. - We recommend setting the
SameSiteattribute toStricton session cookies to reduce cross-site request risks.
For a session cookie impersonation finding:
- Sign session tokens with a tamper-resistant format (e.g. JWTs with appropriate algorithms).
- Authorize the user on every request, not just on login.
Each bullet names the control and what it achieves. None of them repeat controls we already observed working during the test.
Example (too expressive or over-specific)
For an IDOR on a password-change endpoint:
- Extract the user ID exclusively from the user's server-side session and do not accept client-side user IDs passed in the
userparameter of thePOST /api/users/change-passwordendpoint. Compare the user ID retrieved from the session with the target user ID of the password change request, and reject requests where the IDs do not match.- Implement object-level access control for all endpoints under
/api/users/so that every request verifies whether the authenticated user is authorized to modify the specified resource.- We also recommend resetting the administrator password immediately as a mitigation measure and reviewing the application logs for unexpected password changes to determine if the vulnerability has already been exploited.
These bullets read like a patch specification. The first point walks through parameter names, HTTP methods, and comparison logic that belong in the description. The phrasing is also unnaturally formal ("extract exclusively", "client-side user IDs passed in").
A tighter version for the same finding:
- Identify users through tamper resistant session tokens
- Authorize users on every request to user-management endpoints: confirm the logged-in user may change the account they are targeting.
- Reset affected administrator passwords and review logs for signs of exploitation.
The revised bullets state what to fix in plain language, without re-describing the exploit path or sounding like a policy document.
Example (too vague)
- Improve session management.
- Follow security best practices.
- Consider using encryption.
These do not tell the client what to change or where.
Do not recommend what is already in place
During testing we often see partial mitigations or correct settings on related controls. Do not recommend those again.
Before adding a bullet, check whether we already verified the control:
| We observed during testing | Do not recommend |
|---|---|
Session cookies have HttpOnly and Secure | "Set the HttpOnly flag on session cookies" |
| Parameterized queries in the affected endpoint | "Use prepared statements" for that same endpoint |
| MFA enforced for all admin accounts | "Enable MFA for administrators" |
| WAF blocking the exact payload we used | WAF rules as the only fix (note them as interim if code is still vulnerable) |
If a control is present but incomplete (e.g. HttpOnly set but not SameSite), recommend only the missing part: "Set the SameSite attribute to Strict on session cookies."
Address the root cause
Recommendations should close the path we demonstrated in the description. Compensating controls are acceptable as interim measures, but the primary recommendation should fix the underlying issue.
| Finding | Weak recommendation | Strong recommendation |
|---|---|---|
| SQL injection in search | Deploy a WAF rule | Replace string concatenation with prepared statements and stored procedures |
| IDOR on profile API | "Review access controls" | Enforce object-level authorization: verify the authenticated user owns the userId before returning or updating the record |
| Weak TLS cipher suite | "Use strong encryption" | Disable TLS_RSA_WITH_* ciphers on app.example.com and enable only TLS 1.2+ with forward-secret cipher suites |
When we suggest a compensating control (WAF, rate limiting, network segmentation), label it as interim and still recommend the root cause fix.
Pros and cons when fixes are not straightforward
Some recommendations conflict with how the client runs their business, cost money, or break existing workflows. When that applies, add a short note on trade-offs in the same bullet or in a follow-up sentence.
Example (with trade-offs)
For an LDAP relay finding (e.g. NTLM relay to LDAP on a domain controller):
- Enforce LDAP signing and LDAPS channel binding on domain controllers to prevent NTLM relay attacks on LDAP servers. When implementing, follow the sequence recommended by Microsoft to prevent network problems (see linked resources and ADV190023). Legacy applications and OT systems often rely on unsigned LDAP, so inventory and test affected systems before enforcing signing domain-wide.
- If enforcing LDAP signing is not possible, reduce the risk of successful exploitation by configuring the following:
- Add all administrative users to the Protected Users group.
- If adding administrative users to Protected Users is not possible, ensure that at least the Account is sensitive and cannot be delegated flag is set on all admin accounts.
- Disable LLMNR, NBT-NS, and mDNS name resolution in local computer security settings or via Group Policy.
- In addition, implement the following measures:
- Enable Enhanced Protection for Authentication (EPA) on web servers that support AD authentication, and configure them to accept only requests where EPA is enabled. This prevents attackers from relaying NTLM messages into TLS sessions.
- Enable SMB signing on all systems in the network and ensure SMBv1 is no longer supported, to block simpler NTLM relay attacks over SMB.
- Reduce NTLM usage where possible and prefer Kerberos instead.
- Deploy IDS/IPS to detect man-in-the-middle activity and support network-level containment.
- Segment networks and infrastructure components to limit the reach and impact of man-in-the-middle activity.
The first bullet is the primary fix and notes the rollout trade-off. The second bullet gives alternatives when signing cannot be enforced yet. The remaining bullets add defense in depth around the same attack class.
Example (business constraint)
- Restrict VPN access to managed devices through Conditional Access. This closes the relay path we used but may block contractors on personal laptops until an alternative access method is provided.
Be honest about limitations. The client decides whether the trade-off is acceptable.
Order and priority
When multiple bullets are needed, order them by effect:
- Root cause fix (what fully closes the finding).
- Defense in depth (additional hardening that limits blast radius).
- (optional) Interim or compensating controls (while a larger change is planned).
If one action is clearly urgent, say so in the bullet: "As an immediate step, revoke ..."
Common mistakes
- "You should" phrasing instead of a direct verb ("Set", "Remove", "Validate") or "We recommend setting …".
- Generic boilerplate copied from a template without reference to the client's environment.
- Over-specific implementation that repeats the description: parameter names, exact endpoints, or comparison steps instead of naming the control (e.g. "authorize users on every request").
- Stiff or unnatural phrasing such as "derive the authenticated user", "client-supplied identifiers", or long formal sentences that no one would say out loud.
- Expressive or patch-spec wording with long sentences or heavy emphasis.
- Already implemented controls recommended again because we did not check existing settings.
- Symptom-only fixes such as a WAF rule with no mention of fixing vulnerable code.
- Incomplete sentences or fragment bullets like "Parameterized queries."
- Too many bullets listing every hardening guide item when two targeted changes would suffice.
- Missing trade-offs on disruptive changes that the client may reject without discussion.