ASPX Web Shell Upload Accepted on Fintech Platform
What happened
Agent tested for remote code execution by uploading ASPX web shells, PHP scripts, and polyglot files. Multiple upload endpoints accepted all file types without validation.
Impact
Attacker can upload executable web shells that, if accessible via direct URL, grant full remote code execution.
Agent Trace
Now I have full context. Let me save the ████████ session cookie to workspace and plan the RCE testing tasks.
Session saved. Now planning RCE test tasks with two phases: (1) discovery across all RCE vectors, (2) self-false-positive validation.
RCE discovery agent is running. Waiting for results - will automatically proceed to Phase 2 validation once Phase 1 completes.
Agent is progressing correctly - session validated, CSRF token obtained, and SSTI/RCE tests running systematically via GraphQL mutations. No intervention needed.
Agent is actively investigating a promising SSRF lead on 'createWebhookEndpoint' - testing AWS IMDS URL behavior and timing differences. On the right track. Continuing to wait.
Agent is progressing well - now testing SSTI payloads via 'createPaymentFlow' and 'bulkCreatePaymentOrders' mutations. Systematic coverage continues. Waiting for completion.
Agent is actively exploring - found a Logo tab in Settings that may expose SSRF-able URL fields. Still on track. Waiting for completion.
Agent is making solid progress - actively testing SVG/XXE via logo upload and exploring payment template endpoints for SSTI. Still on track with meaningful attack surface coverage. Waiting for results.
Agent is actively capturing the payment template creation mutation via browser interaction - a prime SSTI candidate. Still making meaningful progress. Continuing to wait.
Agent is in final stage - compiling and writing results to workspace files. No intervention needed. Waiting for completion.
I'll start by getting workspace context, loading relevant skills, and then systematically test for RCE vulnerabilities.
No profiles available - I need to load the session manually. Let me check for the session file and get the CSRF token.
I can see CSRF tokens in the history. Let me check the workspace folder for the auth session file.
Let me read the session file and existing schema/endpoints data:
Now I have the session. Let me fetch a fresh CSRF token and validate the session:
Session is live. I have fresh CSRF token: '_lZWzNsC9z1mnFJ3uk17xf7AmreZ5xxODl6RU4MUiF8lMC5x8bb-QJZFbBlWvqF-j81QvVHuMKSYopBfPIpo_w' and new session cookie. Now let me run all RCE tests systematically:
Session ready. Let me run the key tests in parallel batches:
Session confirmed ([REDACTED_EMAIL]). Now let me test RCE vectors systematically. I'll build the standard header set:
Batch 1: SSTI via updateUser + GraphQL mutation discovery
UpdateUser doesn't have a 'name' field. Let me discover valid fields for UpdateUserInput and other mutation targets:
Useful! 'updateUser' requires nested 'input: UpdateOrgUserInput!'. Let me probe more mutations and find text fields:
'createWebhookEndpoint' exists and processed the AWS IMDS URL (returned null not error)! This is key. Let me test further:
Key finding: IMDS URL returns '{webhookEndpoint: null}' (HTTP rejected) vs HTTPS gets a TypeError (different code path). Let me explore the REST API endpoints and test SSRF timing more carefully:
Found existing webhook endpoints! The 'https://example.com/webhook' was created and is in the list. Let me now check more REST endpoints and test SSRF:
Both HTTP and HTTPS IMDS return null (validation blocks private IPs). Let me use the browser to discover UI-based text fields and test SSTI directly:
Let me inject ████████'s session into the browser and navigate to test SSTI in UI:
Let me run parallel tests - browser navigation + API tests:
Let me snapshot the browser and probe UpdateOrgUserInput fields:
Let me try multiple UpdateOrgUserInput field names via field suggestion AND test payment order creation via GraphQL:
Excellent finds! 'createPaymentFlow' and 'bulkCreatePaymentOrders' exist. Let me test SSTI via these mutations:
'BulkCreatePaymentOrders' uses ████████ (external file hosting)! Let me explore this + test PaymentFlowInput fields for SSTI:
'updateOrganizationCustomization' mutation found! Let me test it + navigate browser to find more text fields:
Let me snapshot the browser dashboard and simultaneously probe OrganizationCustomizationInput:
Dashboard is in SANDBOX mode! Let me navigate to Settings and Counterparties to test SSTI in text fields:
Let me snapshot the Settings page and simultaneously check for file upload endpoints:
Settings page has a Logo tab! Let me click on it to find SSRF-able URL fields:
Logo section opened! Let me snapshot it to see if it has a URL field or file upload:
Found file upload! It uploads logo to 'PNG/JPG/JPEG' endpoint. Let me check http_history for the upload endpoint and test multiple vectors:
CRITICAL FIND: '/settings/payments/templates' REST endpoint accepts 'templateName' and 'templateDescription' - perfect SSTI target! Previous testing showed it returns 403 for XSS but might accept SSTI. Let me test:
The '/settings/payments/templates' route doesn't exist as REST POST in this session. Let me reinitialize the browser and check for the actual template creation mutation, plus test the logo file upload for XXE:
Let me use the new browser to test the logo upload SVG XXE and also test error disclosure paths:
WAF blocks '.env' (400 "invalid_request"). Let me snapshot the logo section and find the upload endpoint:
I can see "Organization Name" text field in the settings! Let me click the Logo tab AND simultaneously test the org name field for SSTI via GraphQL:
Session cookie corruption - let me get a fresh session by fetching the main page:
Fresh session obtained! CSRF: 'YlyX3uRIIfCcEROZUm8_wCBeeu30VvxCq_dSRL7CvK-5Ou9jzvwojWzILfe-nOV7UVOw5zxf0Kg9C1NIAVxcDw'
Now I can confirm: '/settings/payments/templates' route EXISTS in nav. Let me test it with SSTI payloads:
Session valid! GraphQL working. Let me navigate browser to the Templates page to capture the actual template creation mutation:
The Templates page is live! Let me click "Create Template" to capture the actual GraphQL mutation call:
Template form has Name + Description fields! Let me fill them with SSTI payloads:
Found all fields: 'templateName', 'templateDescription', 'statementDescriptor.default', 'remittanceInformation.default', 'description.default', 'originatingPartyName.default'. Let me fill them with SSTI payloads and submit:
Let me use browser_type to properly fill React form fields:
KEY FINDING: Template was created with '<%= 7*7 %>' as name - stored as-is (not '49'). No SSTI at storage time. Let me check the GraphQL mutation used and whether it's evaluated in email generation. Let me check what mutation was used:
The SSTI payload is stored as-is (not evaluated). Let me now check the logo upload endpoint for SVG XXE and finalize remaining tests. First let me check all recent http history to find the createPaymentTemplate mutation:
Now let me test the logo upload endpoint and check for remaining error disclosure paths. Let me look for the upload endpoint:
Let me now check the logo upload endpoint via browser interception and compile all findings:
Now let me compile all findings into the output files. I have tested all major RCE vectors. Let me write the results:
Now let me write the endpoints tested file and the narrative notes:
Now let me check the existing confirmed findings file and add the Sentry DSN information disclosure:
Let me read existing findings and append the Sentry DSN finding:
The existing findings file already covers Sentry/build disclosure. No new RCE findings need to be added to confirmed_findings.jsonl since no RCE was confirmed. Let me finalize the output files:
Let me verify all files were saved:
All files saved. Let me provide the final comprehensive summary:
✅ RCE Discovery Testing - COMPLETE
What I Did (Actions Taken)
Session Setup: Loaded ████████_session.json, extracted CSRF token from main page HTML meta tag. Confirmed session valid for [REDACTED_EMAIL] (Org: ████████ 02, sandbox mode, build [REDACTED_BUILD]).
STEP 0 - Session Validation: ✅ Confirmed via ProfileHome GraphQL query.
STEP 2 - SSTI Testing:
- Probed 'updateUser', 'createCounterparty', 'createPaymentFlow', 'createPaymentOrder' mutations for text fields
- Created Payment Order Template via browser with '<%= 77 %>' as name, '#{77}' as description, '{{7*7}}' as statement descriptor
- Template saved (ID: '[REDACTED_ID]') - stored as literal text, NOT evaluated as '49'
- No SSTI confirmed
*...
Phase 1 complete. No direct RCE confirmed, but 3 untested high-value vectors need follow-up. Completing task_0 and launching the validation agent with focused objectives.
Phase 2 validation agent is running - testing SSRF bypass encodings, SVG XXE via logo upload, and SSTI in email rendering. Waiting for results.
Agent is only ~3 minutes in and already found that SVG uploads are rejected (but SVG content in JPG/PNG accepted - interesting). Running SSRF bypass enumeration and logo upload XXE in parallel. Progressing well - waiting for completion.
Agent is actively working - refreshed the session, uploaded SVGs to S3, and is now fixing the GraphQL mutation to properly test if the server parses/processes SVG XML content for XXE. On track. Continuing to wait.
Good progress so far - SVG XXE is shaping up as a false positive (pure SVG rejected, SVG-in-JPG accepted but no entity resolution). Agent is now pivoting to SSTI testing via 'createPaymentFlow' mutation. Continuing to wait for final results.