Opened 8 years ago
Last modified 5 days ago
#46791 reopened defect (bug)
esc_url() adding http:// to a relative URL to parent directory '../pathname/'
| Reported by: | OrangePixelNath | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Future Release |
| Component: | Formatting | Version: | 5.1 |
| Severity: | normal | Keywords: | has-patch has-unit-tests has-test-info |
| Cc: | Focuses: |
Description
esc_url() adds 'http://' when it shouldn't.
Line 4191 wp-includes/formatting.php states
If the URL doesn't appear to contain a scheme, we presume it needs http:// prepended (unless a relative link starting with /, # or ? or a php file).
This is prepending http:// to a relative url to a parent directory i.e. ../path-to-page/
Funtion needs ../ adding to the array or some regex code.
Attachments (2)
Change History (16)
#4
follow-up:
↓ 5
@
7 years ago
- Keywords has-patch added; needs-patch removed
@OrangePixelNath did you mean to close this ticket? If so, can you detail why? What did you discover that made your report incorrect or unnecessary?
#5
in reply to: ↑ 4
@
7 years ago
- Resolution worksforme
- Status closed → reopened
Replying to desrosj:
@OrangePixelNath did you mean to close this ticket? If so, can you detail why? What did you discover that made your report incorrect or unnecessary?
No sorry. I'm new to the system so didn't understand what was next.
#6
@
7 years ago
- Keywords needs-testing added
No problem! That’s why I checked to be sure :)
Next, the ticket stays open for community members to text and review.
#7
@
8 months ago
- Keywords needs-refresh added; needs-testing removed
The patch doesn't apply cleanly; it fails with the error:
Running "patch:46791" (patch) task ? Please select a patch to apply 46791-2.diff (782 bytes) - adde d by subrataemfluence 7 years ago. patching file wp-includes/formatting.php Hunk #1 FAILED at 4190. 1 out of 1 hunk FAILED -- saving rejects to file wp-includes/formatting.php.rej
Patch needs a refresh and removing needs-testing.
This ticket was mentioned in PR #10849 on WordPress/wordpress-develop by @sabernhardt.
8 months ago
#8
- Keywords has-unit-tests added; needs-refresh removed
Does not prepend the fallback protocol when the reference starts with a dot (./ or ../).
This ticket was mentioned in Slack in #core by adrianduffell. View the logs.
3 months ago
#12
@
3 months ago
- Keywords has-test-info added
Patch testing report
Patch / PR tested
- https://github.com/WordPress/wordpress-develop/pull/10849
- trunk @ 1e1d954dfd with PR diff applied (branch
esc_url-relative-paths)
Environment
WordPress: 7.1-beta1-62760-src
PHP: 8.2.18 (Docker)
MySQL: 8.0.36 (Docker)
OS: macOS 26.5.2
Tested via: WP-CLIwp eval+ PHPUnit (server-side formatting function, no UI)
Local wordpress-develop @ http://localhost:8889
Steps
- On trunk, call
esc_url()with directory-relative references and observe the output. - Apply PR #10849 and call
esc_url()with the same inputs. - Confirm non-relative inputs are unaffected (real domains, fragments, queries, scheme'd URLs).
- Run the
escUrlPHPUnit test class.
Results
- Bug on trunk: pass —
esc_url('../parent-directory')returnshttp://../parent-directory(and./, deep../../../../likewise gethttp://prepended). - Fix, parent/current dir: pass —
../parent-directory,./current-directory,../../../../up-four-directoriesare returned unchanged. - Fix, ticket example: pass —
esc_url('../path-to-page/')returns../path-to-page/. - Relative with query/fragment: pass —
./a/b?x=1#ypreserved. - No regression (real domain): pass —
example.comstill returnshttp://example.com. - No regression (other relatives / schemes): pass —
/example.php,example.php,#fragment,?foo=bar,http://example.com/,https://example.com/,ftp://x.com/all unchanged. - Unit tests: pass — full
escUrlclass OK (19 tests, 129 assertions), including the updatedtest_relative()(7 assertions).
Conclusion
PR #10849 adds . to the array of first characters that mark a URL as a relative link in esc_url(), so ./ and ../ directory-relative references are no longer given a fallback http:// prefix. The change is minimal (a one-character functional edit plus a comment update) and well scoped to the ticket, with matching unit-test coverage. No backward-compatibility concern found: real domains and already-scheme'd URLs are unaffected. Minor note: any leading . is now treated as relative (e.g. .hidden stays .hidden), which is harmless since a hostname cannot begin with a bare dot. Recommend commit.
#13
@
3 months ago
- Milestone 7.1 → Future Release
This was brought up in yesterday’s bug scrub and decided to punt.
@sabernhardt it looks like there are a few comments to address on the PR, and then this could probably land in the 7.2 cycle.
qorud02 commented on PR #10849:
5 days ago
#14
Patch testing report
I tested the esc_url() source change from PR #10849 on WordPress 7.2-alpha-64042, PHP 8.4.26, Windows x64. The isolated installation uses SQLite 3.53.4 with SQLite Database Integration 1.8.0, Twenty Twenty-Five and no active regular plugins. This formatting function does not query the database.
I added coverage for an HTTPS-only protocol list, a Korean directory-relative path, and rejected schemes alongside the reported paths. I applied the public PR source hunk, checked that the source bytes changed, ran the same inputs in a fresh PHP process, and restored the original file. I did not run the PHPUnit suite.
Results with the default protocol list
| Input | Before | After |
|---|---|---|
../parent-directory | http://../parent-directory | ../parent-directory
|
./current-directory | http://./current-directory | ./current-directory
|
../../assets/cafe-menu.pdf?ver=1#menu | http://../../assets/cafe-menu.pdf?ver=1#menu | Input preserved |
./한글/메뉴.html | Incorrect http:// prefix | Input preserved, including Korean characters |
.well-known/security.txt | Incorrect http:// prefix | Input preserved |
example.com | http://example.com | Same |
/root/path, ?x=1, #top | Input preserved | Same |
https://example.org/file.pdf | Input preserved | Same |
javascript:alert(1) | Empty string | Same |
data:text/html;base64,AA== | Empty string | Same |
mailto:operator@example.org | Input preserved | Same |
HTTPS-only protocol list
The following additional cases were called with esc_url( $input, array( 'https' ) ):
../parent-directoryand./current-directoryare preserved after the patch.example.comstill receives thehttps://fallback.- Explicit
http://example.org/andjavascript:alert(1)still return an empty string.
Result: the 18-case integration matrix confirms that relative paths are preserved with both the default and HTTPS-only lists, while domain fallback and scheme rejection continue to work in the tested cases.
Public PR diff SHA256: 962b9a7a3309e3ba87bc05d214415b752bd25a701568fe62fc8a8f80e8a07ca1.
WordPress.org username: kyunghan.
AI assistance: OpenAI Codex prepared and executed the scripts and helped draft this report. The before/after outputs were generated by the stated local WordPress installation.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
Proposed patch.