# Security — magento-shippingfields

> **Last verified:** 2026-02-26 (Europe/London)
> **Owner:** Engineering
> **Related:** [GDPR.md](GDPR.md) | [AUDIT.md](AUDIT.md) | [DATA_OWNERSHIP.md](DATA_OWNERSHIP.md)

---

## Access Controls

| Control | Status | Evidence |
|---------|--------|----------|
| REST API authentication | None — anonymous | `src/etc/webapi.xml` — no `authorizationRule` |
| Admin `Update` controller ACL | `Magento_Sales::actions_edit` — confirmed in `_isAllowed()` | `src/Controller/Adminhtml/Order/Update.php` |
| CSRF protection on admin form | `UNKNOWN — Requires Clarification` | Not confirmed from template/controller source |
| Input validation — `shipping_date` | `UNKNOWN — Requires Clarification` | Validation not confirmed in `ShippingFieldsManagement` |
| Input validation — `shipping_message` | Partial — max 255 chars (DB column) | `src/Setup/InstallSchema.php` |

---

## Security Findings

### S1 — HIGH: Synchronous AJAX in checkout — deprecated browser API

| Attribute | Detail |
|-----------|--------|
| Severity | HIGH |
| File | `src/view/frontend/web/js/action/place-order-mixin.js` |

`async: false` on `XMLHttpRequest` is deprecated in browsers and disallowed in some contexts (service workers). Beyond performance, this pattern can make CSRF timing attacks easier since the browser is blocked during the request. It also makes the checkout flow more brittle.

**Recommendation:** Convert to async (`Promise` / `async/await`).

---

### S2 — MEDIUM: REST API endpoint is anonymous — no customer session enforcement

| Attribute | Detail |
|-----------|--------|
| Severity | MEDIUM |
| File | `src/etc/webapi.xml` |

`POST /V1/carts/mine/save-shipping-fields` has no authentication requirement. While `carts/mine` implies the customer's own cart (session-scoped), it may be possible to send crafted requests without a valid session. Data saved is limited to `shipping_date` and `shipping_message` — the attack surface is low but the endpoint is publicly callable.

`UNKNOWN — Requires Clarification`: Does Magento's `carts/mine` endpoint enforce session ownership, or is this endpoint accessible without a valid session?

**Recommendation:** Review whether the endpoint needs authentication. If guest checkout is required, document this decision explicitly.

---

### S3 — MEDIUM: Admin Update controller ACL not confirmed

| Attribute | Detail |
|-----------|--------|
| Severity | MEDIUM |
| File | `src/Controller/Adminhtml/Order/Update.php` |

The admin order update controller modifies order data. If it does not check a specific ACL resource, any admin user could update shipping fields regardless of their role.

ACL resource confirmed: `Magento_Sales::actions_edit` — source-verified in `Update::_isAllowed()`.

**Status:** Resolved — no further action required.

---

### S4 — MEDIUM: shipping_message may contain personal data — logged in plaintext

| Attribute | Detail |
|-----------|--------|
| Severity | MEDIUM |
| Files | `src/Model/ShippingFieldsManagement.php`, `src/Observer/QuoteSubmitBefore.php` |

`shipping_message` is a free-text field. Customers may enter personal details (delivery addresses, instructions referencing names). This field is logged at INFO level without redaction.

**Recommendation:** Avoid logging the full `shipping_message` value. If logging is required for debugging, truncate or mask the content.

---

### S5 — LOW: Input validation gap — shipping_date format not validated server-side

| Attribute | Detail |
|-----------|--------|
| Severity | LOW |
| File | `src/Model/ShippingFieldsManagement.php` |

The `shipping_date` parameter is accepted from the REST API and saved directly to the quote without confirmed server-side format validation. Invalid dates could be stored in the `shipping_date` column.

**Recommendation:** Add server-side format validation (e.g., `Y-m-d` format check) in `ShippingFieldsManagement`.

---

## Personal Data Summary

| Data | Category | Source | Stored Where | Transmitted To |
|------|----------|--------|-------------|----------------|
| `shipping_date` | Non-personal (preference) | Customer checkout input | `quote`, `sales_order` | `magento-orderwebhook` (if installed) |
| `shipping_message` | Potentially personal (free text) | Customer checkout input | `quote`, `sales_order` | `magento-orderwebhook` (if installed) |

---

## Unknowns

1. `UNKNOWN — Requires Clarification`: Does Magento enforce session ownership for `carts/mine` anonymous endpoint?
2. ACL resource confirmed: `Magento_Sales::actions_edit` — source-verified.
3. `UNKNOWN — Requires Clarification`: Is CSRF protection applied to the admin order edit form and `Update` controller?
4. `UNKNOWN — Requires Clarification`: Has a GDPR assessment been completed for the free-text `shipping_message` field?

---

## Evidence

- `/modules/magento-shippingfields/src/etc/webapi.xml`
- `/modules/magento-shippingfields/src/Controller/Adminhtml/Order/Update.php`
- `/modules/magento-shippingfields/src/Model/ShippingFieldsManagement.php`
- `/modules/magento-shippingfields/src/Observer/QuoteSubmitBefore.php`
- `/modules/magento-shippingfields/src/view/frontend/web/js/action/place-order-mixin.js`
- `/modules/magento-shippingfields/src/Setup/InstallSchema.php`
