0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-06 22:40:14 -05:00

Blocked 0.* IP addresses when making oembed requests

no issue

It was possible for authenticated/trusted admin users to make GET requests to localhost via the oembed service by crafting a redirect that used 0.0.0.0.

- added the 0.* default route/routing block to the private IP regex used to block requests when we're contacting external sites
- added an additional IP or localhost check in the oembed service when fetching bookmark card data
This commit is contained in:
Kevin Ansfield 2021-09-14 09:36:12 +01:00 committed by Daniel Lockyer
parent c9325aa2cc
commit 6875796417
4 changed files with 35 additions and 4 deletions

View file

@ -12,8 +12,9 @@ function isPrivateIp(addr) {
/^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) ||
/^f[cd][0-9a-f]{2}:/i.test(addr) ||
/^fe80:/i.test(addr) ||
/^::1$/.test(addr) ||
/^::$/.test(addr);
/^::[10]$/.test(addr) ||
/^::$/.test(addr) ||
/^0/.test(addr);
}
async function errorIfHostnameResolvesToPrivateIp(options) {

View file

@ -101,8 +101,13 @@ class OEmbed {
try {
const cookieJar = new CookieJar();
const response = await this.externalRequest(url, {cookieJar});
const html = response.body;
scraperResponse = await metascraper({html, url});
if (this.isIpOrLocalhost(response.url)) {
scraperResponse = {};
} else {
const html = response.body;
scraperResponse = await metascraper({html, url});
}
} catch (err) {
return Promise.reject(err);
}

View file

@ -126,6 +126,31 @@ describe('Oembed API', function () {
should.exist(res.body.errors);
res.body.errors[0].context.should.match(/insufficient metadata/i);
});
it('errors when fetched url is an IP address', async function () {
const redirectMock = nock('http://test.com/')
.get('/')
.reply(302, undefined, {Location: 'http://0.0.0.0:8080'});
const pageMock = nock('http://0.0.0.0:8080')
.get('/')
.reply(
200,
'<html><head><title>TESTING</title></head><body></body></html>',
{'content-type': 'text/html'}
);
const url = encodeURIComponent('http://test.com');
const res = await request.get(localUtils.API.getApiQuery(`oembed/?type=bookmark&url=${url}`))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(422);
pageMock.isDone().should.be.true();
should.exist(res.body.errors);
res.body.errors[0].context.should.match(/insufficient metadata/i);
});
});
describe('with unknown provider', function () {