Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prebid 9: disallow eval / bidder pair scripts #10653

Closed
patmmccann opened this issue Oct 27, 2023 · 2 comments · Fixed by #11655
Closed

Prebid 9: disallow eval / bidder pair scripts #10653

patmmccann opened this issue Oct 27, 2023 · 2 comments · Fixed by #11655

Comments

@patmmccann
Copy link
Collaborator

patmmccann commented Oct 27, 2023

Type of issue

Feature

Description

At the last Prebid board meeting

eval(publisherTag); // eslint-disable-line no-eval
and #adagio were directed to be resolved by Prebid 9. Bidders having parallel js they appear to use to hide things from publishers or other bidders and to bypass review is not something Prebid.org remains comfortable with.

to close this out we should add a linting rule disallowing loadexternal imports from bid adapters

After merging #11489 and Criteo and (pending) Adagio fixes, we show two bidders continue to import the utility (lucead and improve). Improve only loads for rendering so we can add a lint exception there, as the prebid rendering workflow doesnt meet their needs for reasons detailed elsewhere

@patmmccann
Copy link
Collaborator Author

copy of lucead logic, appears to make client side endpoint requests to several other bidders
`
(() => {
var F = Object.defineProperty,
H = Object.defineProperties;
var Q = Object.getOwnPropertyDescriptors;
var z = Object.getOwnPropertySymbols;
var X = Object.prototype.hasOwnProperty,
Y = Object.prototype.propertyIsEnumerable;
var $ = (e, n, t) => n in e ? F(e, n, {
enumerable: !0,
configurable: !0,
writable: !0,
value: t
}) : e[n] = t,
m = (e, n) => {
for (var t in n || (n = {})) X.call(n, t) && $(e, t, n[t]);
if (z)
for (var t of z(n)) Y.call(n, t) && $(e, t, n[t]);
return e
},
h = (e, n) => H(e, Q(n));

function w() {
    console.log("%cLucead", "background:#444;color:#4EA05D;border-radius:4px;padding:2px", ...arguments)
}

function b() {
    console.error("%cLucead", "background:#444;color:#4EA05D;border-radius:4px;padding:2px", ...arguments)
}
var v = "storage";

function L(e) {
    v = e
}

function Z() {
    let e = JSON.parse(localStorage.getItem(v)) || {};
    for (let n in e)
        if (e.hasOwnProperty(n)) {
            let t = e[n][1] || 0;
            t && t < A() && (delete e[n], k(n, null))
        } return e
}

function j(e) {
    let n = Z();
    return n[e] && n[e][0] || null
}

function k(e, n, t) {
    let o = JSON.parse(localStorage.getItem(v)) || {};
    n ? o[e] = [n, t ? A() + t : 0] : delete o[e], localStorage.setItem(v, JSON.stringify(o)), K()
}

function W(e) {
    k(e, null)
}

function A() {
    return Math.floor(Date.now() / 1e3)
}

function K() {
    let e = JSON.parse(localStorage.getItem(v));
    for (let n in e)
        if (e.hasOwnProperty(n)) {
            let t = e[n][1] || 0;
            t && t < A() && delete e[n]
        } localStorage.setItem(v, JSON.stringify(e))
}
var q = "v0512.1",
    ee = 1500,
    te = !0,
    M = !0;

function C(e) {
    return "response-" + e
}
async function I(e, n = {}) {
    let {
        timeout: t = ee
    } = n, o = new AbortController, r = setTimeout(() => o.abort(), t), p = await fetch(e, h(m({}, n), {
        signal: o.signal,
        credentials: "include"
    }));
    return clearTimeout(r), p
}

function U(e) {
    return e ? e.includes("<html") ? e : `<html lang="en"><body style="margin:0;background-color:#FFF">${e}</body></html>` : null
}

function O(e, n) {
    var o, r, p, i, a, d;
    let t = e.ortbConverter({}).toORTB({
        bidRequests: [n],
        bidderRequest: e.bidderRequest
    });
    if (e.consent ? (e.deepSetValue(t, "user.ext.consent", (o = e == null ? void 0 : e.consent) == null ? void 0 : o.tcString), e.deepSetValue(t, "regs.ext.gdpr", (r = e == null ? void 0 : e.consent) != null && r.gdprApplies ? 1 : 0)) : e.deepSetValue(t, "regs.ext.gdpr", 0), (p = t.imp) != null && p.length)
        for (let l of t.imp) l.banner.w = n.sizes[0][0], l.banner.h = n.sizes[0][1];
    return (a = (i = t == null ? void 0 : t.source) == null ? void 0 : i.ext) != null && a.wrapper || (e.deepSetValue(t, "source.ext.wrapper", "Prebid_js"), e.deepSetValue(t, "source.ext.wrapper_version", (e == null ? void 0 : e.prebid_version) || ((d = window == null ? void 0 : window.pbjs) == null ? void 0 : d.version))), n != null && n.userIdAsEids && e.deepSetValue(t, "user.ext.eids", n.userIdAsEids), e.deepSetValue(t, "device.js", 1), e.deepSetValue(t, "at", 1), e.deepSetValue(t, "cur", ["USD"]), t
}

function T(e, n, t = null) {
    var p;
    if (!((p = e == null ? void 0 : e.seatbid) != null && p.length)) return null;
    let o = e.seatbid[0].bid.filter(i => i && i.price > 0 && i.adm && i.w === n.width && i.h === n.height);
    o.sort((i, a) => a.price - i.price);
    let r = o[0];
    return {
        cpm: (r == null ? void 0 : r.price) || 0,
        currency: e.cur || "USD",
        ad: U((r == null ? void 0 : r.adm) || null),
        size: {
            width: (r == null ? void 0 : r.w) || n.width,
            height: (r == null ? void 0 : r.h) || n.height
        },
        ssp: t,
        advertiser_domains: (r == null ? void 0 : r.adomain) || null
    }
}
async function ne() {
    return new Promise(e => {
        window.__tcfapi ? window.__tcfapi("getTCData", 2, (n, t) => {
            e(t ? n : null)
        }) : e(null)
    })
}
async function re(e) {
    try {
        return await fetch(`${e.static_url}/placements/info?ids=` + e.bidRequests.map(n => n == null ? void 0 : n.params.placementId).join(",")).then(n => n.json())
    } catch (n) {
        return null
    }
}
async function oe({
    lb_url: e,
    base_url: n,
    size: t,
    placement_id: o,
    bidRequest: r,
    bidderRequest: p,
    floor: i,
    is_sra: a,
    endpoint_url: d
}) {
    t || (t = {
        width: 300,
        height: 250
    });
    let l = n,
        S = {
            seller: l,
            decisionLogicUrl: `${l}/js/ssp.js`,
            interestGroupBuyers: [l],
            auctionSignals: {
                size: t,
                placement_id: o
            },
            requestedSize: t,
            allSlotsRequestedSizes: [t],
            sellerSignals: {},
            sellerTimeout: 1e3,
            sellerCurrency: "EUR",
            perBuyerSignals: {
                [l]: {
                    prebid_bid_id: r == null ? void 0 : r.bidId,
                    prebid_request_id: p == null ? void 0 : p.bidderRequestId,
                    placement_id: o,
                    floor: i,
                    is_sra: a,
                    endpoint_url: d
                }
            },
            perBuyerTimeouts: {
                "*": 1e3
            },
            resolveToConfig: !1,
            dataVersion: 2,
            deprecatedReplaceInURN: {
                "${PLACEMENT_ID}": o
            }
        },
        s;
    if (!navigator.runAdAuction || location.hash.includes("skip-pa") ? s = null : s = await navigator.runAdAuction(S), s) {
        if (await navigator.deprecatedReplaceInURN(s, {
                "${PLACEMENT_ID}": o
            }), te) {
            let _ = document.createElement("iframe");
            _.src = s, _.style.display = "none", document.body.appendChild(_), _.remove()
        }
        return {
            bid_id: r == null ? void 0 : r.bidId,
            ad: U(`<iframe src="${s}" style="width:${t.width}px;height:${t.height}px;border:none" seamless ></iframe>`),
            size: t,
            is_pa: !0,
            placement_id: o
        }
    } else return null
}
async function ie(e) {
    let n = e.placements_info;
    return await Promise.all(e.bidRequests.map(async t => {
        var p, i, a, d, l, S, s, _, P, J, D, E;
        let o = {
            bid_id: t == null ? void 0 : t.bidId,
            bid: 0,
            ad: null,
            size: null,
            placement_id: e.placement_id
        };
        if (((p = t == null ? void 0 : t.params) == null ? void 0 : p.enableContextual) === !1) return o;
        let r = {
            width: t.sizes[0][0] || 300,
            height: t.sizes[0][1] || 250
        };
        try {
            let g = (i = t == null ? void 0 : t.params) == null ? void 0 : i.placementId;
            if (!g) return o;
            let G = await oe(h(m({}, e), {
                size: r,
                placement_id: g,
                data: e,
                bidRequest: t
            }));
            if (G) return G;
            let c = n[g] || null;
            if (!(c != null && c.ssps)) return w("No placement info", g, n), o;
            if (M) {
                let u = j(C(g));
                if (u) return u.bid_id = t.bidId, u
            }
            let y = [];
            if ((a = c == null ? void 0 : c.ssps) != null && a.improve && y.push(se(h(m({}, e), {
                    size: r,
                    placement_id: (d = c == null ? void 0 : c.ssps) == null ? void 0 : d.improve,
                    data: e,
                    bidRequest: t
                }))), (l = c == null ? void 0 : c.ssps) != null && l.grid && y.push(ce(h(m({}, e), {
                    size: r,
                    placement_id: c == null ? void 0 : c.ssps.grid,
                    deepSetValue: e.deepSetValue,
                    data: e,
                    bidRequest: t
                }))), (S = c == null ? void 0 : c.ssps) != null && S.smart && y.push(le(h(m({}, e), {
                    sizes: t.sizes,
                    size: r,
                    placement_id: (s = c == null ? void 0 : c.ssps) == null ? void 0 : s.smart,
                    transaction_id: t.transactionId,
                    bid_id: t.bidId,
                    ad_unit_code: t.adUnitCode,
                    deepSetValue: e.deepSetValue,
                    data: e,
                    bidRequest: t
                }))), (_ = c == null ? void 0 : c.ssps) != null && _.pubmatic && y.push(ae(h(m({}, e), {
                    size: r,
                    placement_id: (P = c == null ? void 0 : c.ssps) == null ? void 0 : P.pubmatic,
                    transaction_id: t.transactionId,
                    bid_id: t.bidId,
                    ad_unit_code: t.adUnitCode,
                    data: e,
                    bidRequest: t
                }))), (J = c == null ? void 0 : c.ssps) != null && J.magnite && y.push(pe(h(m({}, e), {
                    size: r,
                    placement_id: (D = c == null ? void 0 : c.ssps) == null ? void 0 : D.magnite,
                    ad_unit_code: t.adUnitCode,
                    data: e,
                    bidRequest: t,
                    placement: c
                }))), !y.length) return o;
            let f = await Promise.all(y);
            if (f === null || !(f != null && f.length)) return o;
            if (f = f.filter(u => u && u.cpm), f != null && f.length) {
                (E = f[0]) != null && E.is_pa || f.sort((x, V) => ((V == null ? void 0 : V.cpm) || 0) - ((x == null ? void 0 : x.cpm) || 0));
                let u = f[0];
                if (u.bid_id = t.bidId, u.size = r, u.placement_id = g, M) {
                    let x = `<script>top.ayads_rendered("${g}")<\/script>`;
                    u.ad.includes("</body>") ? u.ad = u.ad.replace("</body>", x + "</body>") : u.ad += x, k(C(g), u, 86400)
                }
                return u
            } else return o
        } catch (g) {
            return b(g), o
        }
    }))
}
async function B(e) {
    w("Lucead for Prebid ", q, e);
    let n = e.endpoint_url.replace("/go", ""),
        t = e.request_id,
        [o, r] = await Promise.all([re(e), ne()]);
    e.consent = r, e.placements_info = o;
    let p = null;
    try {
        p = await ie(e)
    } catch (i) {
        b(i)
    }
    fetch(`${n}/go/prebid/pub`, {
        method: "POST",
        contentType: "text/plain",
        body: JSON.stringify({
            request_id: t,
            responses: p,
            is_sra: e.is_sra
        })
    }).catch(b)
}
window.ayads_rendered = function(e) {
    let n = C(e);
    w("rendered", e, j(n)), W(n)
};
var N = location.hash.includes("mock");
async function se({
    data: e,
    bidRequest: n,
    prebid_version: t,
    size: o,
    placement_id: r
}) {
    var a, d;
    let p = N ? "?mock=improve" : "https://ad.360yield.com/pb",
        i = O(e, n);
    i.imp[0].ext.bidder = {
        placementId: r || 22511670
    }, i.ext = {
        improvedigital: {
            sdk: {
                name: "pbjs",
                version: t || "8.32.0"
            }
        }
    };
    try {
        performance.mark("lucead-improve-start");
        let l = await I(p, {
            method: "POST",
            contentType: "text/plain",
            body: JSON.stringify(i)
        });
        return l.status !== 200 || (l = await l.json(), !((d = (a = l == null ? void 0 : l.seatbid[0]) == null ? void 0 : a.bid[0]) != null && d.price)) ? null : (performance.mark("lucead-improve-end"), T(l, o, "improve"))
    } catch (l) {
        return null
    }
}
async function ce({
    size: e,
    placement_id: n,
    data: t,
    bidRequest: o
}) {
    let r = N ? "?mock=grid" : "https://grid.bidswitch.net/hbjson",
        p = O(t, o);
    p.imp[0].tagid = n.toString();
    try {
        let i = await I(r, {
            method: "POST",
            contentType: "text/plain",
            body: JSON.stringify(p)
        });
        return i.status !== 200 ? (w("Grid response not ok", i), null) : (i = await i.json(), T(i, e, "grid"))
    } catch (i) {
        return null
    }
}
async function le({
    placement_id: e,
    sizes: n,
    size: t,
    prebid_version: o,
    transaction_id: r,
    bid_id: p,
    ad_unit_code: i,
    consent: a
}) {
    let d = "https://prg.smartadserver.com/prebid/v1",
        l = e.toString().split(":").map(s => parseInt(s));
    if (l.length < 3) return null;
    let S = {
        siteid: l[0] || 351627,
        pageid: l[1] || 1232283,
        formatid: l[2] || 88269,
        ckid: l[3] || 0,
        tagId: i,
        pageDomain: location.href,
        transactionId: r,
        timeout: 3e3,
        bidId: p,
        prebidVersion: o || "8.37.0",
        schain: pbjs.getConfig("schain"),
        gpid: i,
        sizes: n.map(s => ({
            w: s[0],
            h: s[1]
        })),
        bidfloor: 0,
        gdpr_consent: (a == null ? void 0 : a.tcString) || null
    };
    try {
        let s = await I(d, {
            method: "POST",
            contentType: "text/plain",
            body: JSON.stringify(S)
        });
        return !s.ok || s.status !== 200 || s.headers.get("content-length") === "0" ? (w("Response not ok", s), null) : (s = await s.json(), s ? {
            cpm: (s == null ? void 0 : s.cpm) || 0,
            currency: (s == null ? void 0 : s.currency) || "USD",
            ad: s != null && s.ad ? U(s.ad) : null,
            size: {
                width: s.width || t.width,
                height: s.height || t.height
            },
            ssp: "smart"
        } : null)
    } catch (s) {
        return null
    }
}
async function ae({
    placement_id: e,
    size: n,
    data: t,
    bidRequest: o
}) {
    let r = N ? "?mock=pubmatic" : "https://hbopenbid.pubmatic.com/translator?source=prebid-client",
        [p, i] = e.toString().split(":"),
        a = O(t, o);
    a.at = 1, a.cur = ["USD"], a.imp[0].tagid = i, a.imp[0].secure = 1, a.imp[0].banner.pos = 0, a.site.publisher.id = p;
    try {
        let d = await I(r, {
            method: "POST",
            contentType: "text/plain",
            body: JSON.stringify(a)
        });
        return d.ok ? (d = await d.json(), T(d, n, "pubmatic")) : (w("Response not ok", d), null)
    } catch (d) {
        return null
    }
}
async function pe({
    placement_id: e,
    size: n,
    ad_unit_code: t,
    data: o,
    bidRequest: r,
    placement: p
}) {
    let i = N ? "?mock=magnite" : "https://prebid-server.rubiconproject.com/openrtb2/auction",
        a = e.toString().split(":").map(l => parseInt(l));
    if (a.length < 3) return null;
    let d = O(o, r);
    d.imp[0].ext.prebid = {
        bidder: {
            rubicon: {
                video: {},
                accountId: a[0],
                siteId: a[1],
                zoneId: a[2]
            }
        },
        adunitcode: t
    };
    try {
        let l = await I(i, {
            method: "POST",
            contentType: "text/plain",
            body: JSON.stringify(d)
        });
        return l.ok ? (l = await l.json(), T(l, n, "magnite", p)) : null
    } catch (l) {
        return null
    }
}
L("lucead");
window.ayads_prebid = B;
window.lucead_prebid = B;

})();`

@patmmccann
Copy link
Collaborator Author

Marking as ready for dev on the linting rule

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging a pull request may close this issue.

1 participant