EverTrust Finance — secure financial-services application
A production financial-services platform handling loan applications, sensitive customer documents and administrative workflows, protected through layered authentication, access control, secure file handling and production hardening.
Project overview
EverTrust Finance is a production financial-services web application supporting loan applications and related customer, document and administrative workflows.
The application processes security-sensitive information and uploaded documents, making confidentiality, access control and secure file handling important parts of the system design.
My work on the platform combines PHP development with application security engineering, including secure code review, authentication and authorisation controls, secure file handling, administrative-access protection, application hardening, vulnerability remediation and security retesting.
Because this is a production financial-services application, this portfolio intentionally excludes private endpoints, customer information, credentials, infrastructure details and other sensitive implementation information.
My role
My responsibilities have included:
- PHP application development
- application security review
- authentication security
- server-side authorisation
- administrative-access hardening
- MFA/2FA implementation
- password-policy enforcement
- session security
- CSRF protection
- rate limiting
- anti-automation controls
- secure file-upload design
- input validation
- vulnerability remediation
- security retesting
- production hardening
- security monitoring
- protection of sensitive application workflows
The objective is not only to identify vulnerabilities but to implement security controls that work within a real production application.
Security architecture
The platform uses defence in depth rather than relying on a single security control.
At a high level:
Internet
|
v
Cloudflare security / access layer
|
v
Web application
|
+--------------------------+
| |
v v
Public workflows Protected administration
|
+-- MFA/2FA
+-- strong authentication
+-- server-side authorisation
+-- rate limiting
+-- anti-automation controls
+-- CSRF protection
+-- session hardening
|
v
Sensitive operations
The exact administrative routes and internal infrastructure are intentionally not published.
Protected administrative access
Administrative functionality is treated as a separate security boundary.
The administrative interface is protected through multiple controls rather than relying on an obscure URL.
These controls include:
- Cloudflare Zero Trust as an additional access layer
- application authentication
- MFA/2FA
- server-side authorisation
- strong password requirements
- login rate limiting
- anti-automation controls
- hardened session handling
- CSRF protection
This provides multiple opportunities to stop unauthorised access before sensitive administrative functionality can be reached.
Cloudflare Zero Trust
Administrative access is placed behind an additional Cloudflare Zero Trust layer.
This means reaching the application login is not intended to be the only security boundary protecting administrative functionality.
The design follows a defence-in-depth principle:
External request
|
v
Access layer
|
v
Application authentication
|
v
MFA/2FA
|
v
Server-side authorisation
|
v
Administrative action
Failure of one control should not automatically provide access to the protected functionality.
Authentication
Authentication controls were designed around the sensitivity of the application.
The password policy requires a minimum of 12 characters together with defined complexity requirements.
Authentication is combined with MFA/2FA for protected administrative access.
The application does not treat knowledge of an administrative URL as an authentication mechanism.
The security boundary is enforced by the controls behind the route.
Rate limiting
Authentication endpoints are rate limited to reduce repeated automated login attempts.
Rate limiting does not replace strong authentication, but it increases the cost of automated password attacks and provides an additional defensive layer around exposed authentication functionality.
The important principle is:
A public authentication endpoint should assume that automated requests will eventually reach it.
Honeypot protection
Anti-automation protection also includes honeypot controls.
A honeypot field is designed to remain empty during normal human interaction but may be populated by simplistic automated form-filling tools.
This provides an additional signal for rejecting suspicious submissions.
Honeypots are treated as defence in depth rather than as the primary authentication control.
Server-side authorisation
Authentication and authorisation are treated as separate security decisions.
Authentication answers:
Who is this user?
Authorisation answers:
Is this user permitted to perform this action
on this specific resource?
Sensitive application functionality therefore requires server-side authorisation rather than relying on hidden interface elements or knowledge of a particular route.
This is especially important for financial records, customer information and uploaded documents.
CSRF protection
State-changing operations are protected against Cross-Site Request Forgery.
CSRF tokens are generated and validated server-side, with timing-safe comparison using hash_equals() where custom token comparison is performed.
Conceptually:
if (
!isset($_SESSION['csrf_token'], $_POST['csrf_token']) ||
!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])
) {
http_response_code(403);
exit('Invalid request.');
}
The important security property is that possession of an authenticated browser session alone is not sufficient for another website to cause arbitrary sensitive actions.
Secure file uploads
Document upload is a particularly security-sensitive part of the application.
The platform accepts customer documents required for financial workflows, so uploaded files are treated as untrusted input.
The upload process uses several independent controls:
Incoming upload
|
v
Request / file validation
|
v
Extension allowlist
|
v
finfo MIME inspection
|
v
Server-generated random filename
|
v
Storage outside public web root
|
v
Application-controlled access
No single check is treated as sufficient by itself.
Extension allowlisting
Only explicitly permitted file extensions are accepted.
Conceptually:
$allowedExtensions = [
'pdf',
'jpg',
'jpeg',
'png',
];
$extension = strtolower(
pathinfo($originalName, PATHINFO_EXTENSION)
);
if (!in_array($extension, $allowedExtensions, true)) {
throw new RuntimeException('File type not permitted.');
}
An allowlist is preferred to attempting to enumerate every dangerous extension.
However, extension validation alone is not considered sufficient.
MIME validation with finfo
The application does not rely solely on the browser-supplied Content-Type value.
Uploaded files are inspected server-side using PHP's finfo functionality.
Conceptually:
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($temporaryPath);
$allowedMimeTypes = [
'application/pdf',
'image/jpeg',
'image/png',
];
if (!in_array($mime, $allowedMimeTypes, true)) {
throw new RuntimeException('File type not permitted.');
}
This checks the server-observed file type rather than trusting metadata supplied by the client.
Extension and MIME validation are used together as layered controls.
Randomised filenames
User-supplied filenames are not trusted as permanent storage names.
The application generates a random filename using cryptographically secure random data.
For example:
$storedName = bin2hex(random_bytes(32));
The validated extension can then be associated with the generated storage name where required.
This prevents the application from relying directly on attacker-controlled filenames and also reduces filename collisions and predictability.
Storage outside the web root
Uploaded customer documents are stored outside the publicly accessible web directory.
This is an important security boundary.
A successful upload should not automatically create a directly web-accessible file such as:
https://example.com/uploads/user-file.php
Instead:
Browser
|
X---- no direct access ----> Private document storage
Authenticated application
|
+---- authorisation check
|
v
Private document storage
The application controls access to stored documents.
This substantially reduces the risk associated with treating an uploaded file as public web content.
Why multiple upload controls matter
File-upload security should not depend on one validation check.
For example:
Extension check only
does not establish the actual file type.
Similarly:
Content-Type: image/jpeg
cannot automatically be trusted because the request is controlled by the client.
The defensive strategy therefore combines:
- extension allowlisting
- server-side MIME inspection
- server-generated filenames
- storage outside the web root
- application-level access control
This is defence in depth.
Input validation
All user-controlled input is treated as untrusted.
This includes values originating from legitimate application forms because requests can be intercepted and modified before reaching the server.
Validation is therefore performed server-side.
Security decisions are not based solely on:
- HTML input restrictions
- hidden fields
- JavaScript validation
- disabled form controls
- values generated by the frontend
The server remains responsible for deciding whether a request is valid and authorised.
Session security
Administrative authentication establishes a security-sensitive session.
Session handling is hardened so that authentication state is protected independently of the application's visible interface.
Session security is considered alongside:
- authentication
- MFA/2FA
- authorisation
- CSRF protection
- logout behaviour
- secure cookie configuration
- privilege-sensitive operations
The objective is to ensure that authentication remains trustworthy after login, not merely during credential submission.
Production hardening
Application security extends beyond PHP business logic.
Production hardening also considers:
- HTTPS
- secure application configuration
- production error handling
- filesystem permissions
- public document-root exposure
- protection of environment configuration
- separation of secrets from source code
- unnecessary information disclosure
- access to sensitive administrative functionality
- security monitoring
This reduces the surrounding attack surface available to an attacker.
Sensitive-data handling
A financial-services application processes information that should not be unnecessarily exposed.
Security design therefore follows principles including:
- collect only information required by the business workflow
- restrict access to authorised users
- avoid exposing private documents through predictable public paths
- avoid writing credentials and secrets into source code
- avoid unnecessary sensitive information in logs
- control access to uploaded documents through the application
- sanitise information before using it as portfolio evidence
Customer records and uploaded documents are never used as public portfolio examples.
Secure development and remediation
When a security issue is identified, the objective is to fix the underlying security assumption rather than only blocking one payload.
The workflow is:
Identify
|
v
Reproduce safely
|
v
Find root cause
|
v
Implement remediation
|
v
Retest original issue
|
v
Test related behaviour
This is particularly important in production because a security fix must close the vulnerability without breaking legitimate customer or administrative workflows.
Retesting
Security remediation is followed by retesting.
Both positive and negative behaviour are important.
For example:
Authorised user + valid resource
|
v
ALLOWED
while:
Authenticated user + unauthorised resource
|
v
REJECTED
Testing only the rejected request is insufficient if the security change accidentally prevents legitimate users from completing their work.
Security monitoring
Application hardening is complemented by security monitoring.
Security-relevant activity can include:
- repeated authentication failures
- suspicious request patterns
- access-control failures
- application errors
- administrative activity
- abnormal behaviour around sensitive functionality
Monitoring does not replace preventive controls, but it adds visibility when those controls are exercised or attacked.
Security through obscurity
One design lesson from administrative interfaces is that changing or hiding a route should never be treated as the primary security control.
An attacker should be assumed capable of discovering application endpoints.
Security must therefore remain effective even when the endpoint is known.
The real controls are:
- access-layer protection
- authentication
- MFA/2FA
- authorisation
- rate limiting
- secure sessions
- CSRF protection
- monitoring
An undisclosed route can reduce unnecessary noise, but it does not replace these controls.
Confidentiality and responsible disclosure
EverTrust Finance is a real production financial-services application.
For that reason, this portfolio intentionally does not publish:
- exact administrative routes
- customer names
- customer financial information
- NIN or IPPIS information
- bank details
- uploaded identity documents
- payslips
- bank statements
- credentials
- API keys
- authentication tokens
- session identifiers
- private source code
- private network information
- detailed production infrastructure
- unresolved security findings
Examples on this portfolio are sanitised, simplified or recreated where necessary to explain the security principle without exposing sensitive production information.
What this project demonstrates
EverTrust demonstrates the combination of development and application security required to protect a real production system.
The project has required me to think about security across multiple layers:
Identity
+
Authentication
+
MFA
+
Authorisation
+
Session security
+
CSRF protection
+
Rate limiting
+
Secure file handling
+
Infrastructure hardening
+
Monitoring
No individual control is expected to protect the entire application.
The security model relies on layers.
Key lessons
- Authentication and authorisation solve different security problems.
- Administrative routes must remain secure even when their location is known.
- MFA provides an important additional control for privileged access.
- Rate limiting and honeypots complement authentication but do not replace it.
- CSRF protection belongs on state-changing authenticated operations.
- Browser-provided file metadata cannot be trusted by itself.
- File extensions and MIME types should be validated using an allowlist.
- Uploaded filenames should not be trusted as storage identifiers.
- Sensitive uploads are safer when stored outside the public web root.
- Production hardening must cover both the application and its surrounding environment.
- Defence in depth is especially important when an application handles financial and identity information.
- A security remediation is not complete until the legitimate workflow and the original attack condition have both been retested.