CVE-2017-0907 (C#, published 2017-11-13T17:29Z)
Description: value: The Recurly Client .NET Library before 1.0.1, 1.1.10, 1.2.8, 1.3.2, 1.4.14, 1.5.3, 1.6.2, 1.7.1, 1.8.1 is vulnerable to a Server-Side Request Forgery vulnerability due to incorrect use of "Uri.EscapeUriString" that could result in compromise of API keys or other critical resources.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-918 \u2014 Server-Side Request Forgery (SSRF)
The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.
Repository: https://github.com/recurly/recurly-client-net
Files changed:
Library/Account.cs
Library/AccountBalance.cs
Library/AddOn.cs
Library/Adjustment.cs
Library/BillingInfo.cs
Library/Coupon.cs
Library/CouponRedemption.cs
Library/Export.cs
Library/GiftCard.cs
Library/Invoice.cs
Library/MeasuredUnit.cs
Library/Plan.cs
Library/Subscription.cs
Library/Transaction.cs
Commit message: SSRF fix: replace EscapeUriString with EscapeDataString


Vulnerable code:
                UrlPrefix + Uri.EscapeUriString(AccountCode) + "/billing_info");
                UrlPrefix + Uri.EscapeUriString(AccountCode),
                UrlPrefix + Uri.EscapeUriString(AccountCode) + "/invoices",
                UrlPrefix + Uri.EscapeUriString(AccountCode) + "/invoices/preview",
                UrlPrefix + Uri.EscapeUriString(AccountCode) + "/adjustments/"
                UrlPrefix + Uri.EscapeUriString(AccountCode) + "/shipping_addresses/",
            return new SubscriptionList(UrlPrefix + Uri.EscapeUriString(AccountCode) + "/subscriptions/"
            return new TransactionList(UrlPrefix + Uri.EscapeUriString(AccountCode) + "/transactions/"
            return new NoteList(UrlPrefix + Uri.EscapeUriString(AccountCode) + "/notes/");
                UrlPrefix + Uri.EscapeUriString(AccountCode) + "/redemptions",
                UrlPrefix + Uri.EscapeUriString(accountCode),
                Account.UrlPrefix + Uri.EscapeUriString(accountCode));
                Account.UrlPrefix + Uri.EscapeUriString(accountCode) + "/reopen");
                UrlPrefix + Uri.EscapeUriString(accountCode) + "/balance", accountBalance.ReadXml);
                UrlPrefix + Uri.EscapeUriString(PlanCode) + UrlPostfix,
                UrlPrefix + Uri.EscapeUriString(PlanCode) + UrlPostfix + Uri.EscapeUriString(AddOnCode),
                UrlPrefix + Uri.EscapeUriString(PlanCode) + UrlPostfix + Uri.EscapeUriString(AddOnCode));
                UrlPrefix + Uri.EscapeUriString(AccountCode) + UrlPostfix,
                UrlPostfix + Uri.EscapeUriString(Uuid));
                "/adjustments/" + Uri.EscapeUriString(uuid),
            return UrlPrefix + Uri.EscapeUriString(accountCode) + UrlPostfix;
                UrlPrefix + Uri.EscapeUriString(CouponCode),
                UrlPrefix + Uri.EscapeUriString(CouponCode) + "/restore",
                UrlPrefix + Uri.EscapeUriString(CouponCode));
                Coupon.UrlPrefix + Uri.EscapeUriString(couponCode),
               "/coupons/" + Uri.EscapeUriString(couponCode) + "/redeem",
                "/accounts/" + Uri.EscapeUriString(AccountCode) +
                "/redemptions/" + Uri.EscapeUriString(Uuid));
                string.Format(ExportFile.FileUrlPrefix, date.ToString("yyyy-MM-dd"), Uri.EscapeUriString(fileName)),
                UrlPrefix + Uri.EscapeUriString(id.ToString()),
                "/accounts/" + Uri.EscapeUriString(accountCode) + Invoice.UrlPrefix,
                "/accounts/" + Uri.EscapeUriString(accountCode) + Invoice.UrlPrefix + "preview",
            return new InvoiceList("/accounts/" + Uri.EscapeUriString(accountCode) + "/invoices");
                "/accounts/" + Uri.EscapeUriString(accountCode) + Invoice.UrlPrefix,
                UrlPrefix + Uri.EscapeUriString(Id.ToString()),
                UrlPrefix + Uri.EscapeUriString(Id.ToString()));
                    var url = UrlPrefix + Uri.EscapeUriString(PlanCode) + "/add_ons/";
                UrlPrefix + Uri.EscapeUriString(PlanCode),
            Client.Instance.PerformRequest(Client.HttpRequestMethod.Delete, UrlPrefix + Uri.EscapeUriString(PlanCode));
                UrlPrefix + Uri.EscapeUriString(PlanCode) + "/add_ons/" + Uri.EscapeUriString(addOnCode),
                Plan.UrlPrefix + Uri.EscapeUriString(planCode),
                UrlPrefix + Uri.EscapeUriString(Uuid),
                UrlPrefix + Uri.EscapeUriString(Uuid) + "/cancel",
                UrlPrefix + Uri.EscapeUriString(Uuid) + "/reactivate",
                UrlPrefix + Uri.EscapeUriString(Uuid) + "/terminate?refund=" + refund.ToString().EnumNameToTransportCase(),
                UrlPrefix + Uri.EscapeUriString(Uuid) + "/preview",
                UrlPrefix + Uri.EscapeUriString(Uuid) + "/postpone?next_renewal_date=" + nextRenewalDate.ToString("s") + "&bulk=" + bulk.ToString().ToLower(),
                UrlPrefix + Uri.EscapeUriString(Uuid) + "/notes",
                UrlPrefix + Uri.EscapeUriString(Uuid) + "/redemptions/",
                Subscription.UrlPrefix + Uri.EscapeUriString(uuid),
                UrlPrefix + Uri.EscapeUriString(Uuid) + (refund.HasValue ? "?amount_in_cents=" + refund.Value : ""),
                Transaction.UrlPrefix + Uri.EscapeUriString(transactionId),

Fixed code:
                UrlPrefix + Uri.EscapeDataString(AccountCode) + "/billing_info");
                UrlPrefix + Uri.EscapeDataString(AccountCode),
                UrlPrefix + Uri.EscapeDataString(AccountCode) + "/invoices",
                UrlPrefix + Uri.EscapeDataString(AccountCode) + "/invoices/preview",
                UrlPrefix + Uri.EscapeDataString(AccountCode) + "/adjustments/"
                UrlPrefix + Uri.EscapeDataString(AccountCode) + "/shipping_addresses/",
            return new SubscriptionList(UrlPrefix + Uri.EscapeDataString(AccountCode) + "/subscriptions/"
            return new TransactionList(UrlPrefix + Uri.EscapeDataString(AccountCode) + "/transactions/"
            return new NoteList(UrlPrefix + Uri.EscapeDataString(AccountCode) + "/notes/");
                UrlPrefix + Uri.EscapeDataString(AccountCode) + "/redemptions",
                UrlPrefix + Uri.EscapeDataString(accountCode),
                Account.UrlPrefix + Uri.EscapeDataString(accountCode));
                Account.UrlPrefix + Uri.EscapeDataString(accountCode) + "/reopen");
                UrlPrefix + Uri.EscapeDataString(accountCode) + "/balance", accountBalance.ReadXml);
                UrlPrefix + Uri.EscapeDataString(PlanCode) + UrlPostfix,
                UrlPrefix + Uri.EscapeDataString(PlanCode) + UrlPostfix + Uri.EscapeDataString(AddOnCode),
                UrlPrefix + Uri.EscapeDataString(PlanCode) + UrlPostfix + Uri.EscapeDataString(AddOnCode));
                UrlPrefix + Uri.EscapeDataString(AccountCode) + UrlPostfix,
                UrlPostfix + Uri.EscapeDataString(Uuid));
                "/adjustments/" + Uri.EscapeDataString(uuid),
            return UrlPrefix + Uri.EscapeDataString(accountCode) + UrlPostfix;
                UrlPrefix + Uri.EscapeDataString(CouponCode),
                UrlPrefix + Uri.EscapeDataString(CouponCode) + "/restore",
                UrlPrefix + Uri.EscapeDataString(CouponCode));
                Coupon.UrlPrefix + Uri.EscapeDataString(couponCode),
               "/coupons/" + Uri.EscapeDataString(couponCode) + "/redeem",
                "/accounts/" + Uri.EscapeDataString(AccountCode) +
                "/redemptions/" + Uri.EscapeDataString(Uuid));
                string.Format(ExportFile.FileUrlPrefix, date.ToString("yyyy-MM-dd"), Uri.EscapeDataString(fileName)),
                UrlPrefix + Uri.EscapeDataString(id.ToString()),
                "/accounts/" + Uri.EscapeDataString(accountCode) + Invoice.UrlPrefix,
                "/accounts/" + Uri.EscapeDataString(accountCode) + Invoice.UrlPrefix + "preview",
            return new InvoiceList("/accounts/" + Uri.EscapeDataString(accountCode) + "/invoices");
                "/accounts/" + Uri.EscapeDataString(accountCode) + Invoice.UrlPrefix,
                UrlPrefix + Uri.EscapeDataString(Id.ToString()),
                UrlPrefix + Uri.EscapeDataString(Id.ToString()));
                    var url = UrlPrefix + Uri.EscapeDataString(PlanCode) + "/add_ons/";
                UrlPrefix + Uri.EscapeDataString(PlanCode),
            Client.Instance.PerformRequest(Client.HttpRequestMethod.Delete, UrlPrefix + Uri.EscapeDataString(PlanCode));
                UrlPrefix + Uri.EscapeDataString(PlanCode) + "/add_ons/" + Uri.EscapeDataString(addOnCode),
                Plan.UrlPrefix + Uri.EscapeDataString(planCode),
                UrlPrefix + Uri.EscapeDataString(Uuid),
                UrlPrefix + Uri.EscapeDataString(Uuid) + "/cancel",
                UrlPrefix + Uri.EscapeDataString(Uuid) + "/reactivate",
                UrlPrefix + Uri.EscapeDataString(Uuid) + "/terminate?refund=" + refund.ToString().EnumNameToTransportCase(),
                UrlPrefix + Uri.EscapeDataString(Uuid) + "/preview",
                UrlPrefix + Uri.EscapeDataString(Uuid) + "/postpone?next_renewal_date=" + nextRenewalDate.ToString("s") + "&bulk=" + bulk.ToString().ToLower(),
                UrlPrefix + Uri.EscapeDataString(Uuid) + "/notes",
                UrlPrefix + Uri.EscapeDataString(Uuid) + "/redemptions/",
                Subscription.UrlPrefix + Uri.EscapeDataString(uuid),
                UrlPrefix + Uri.EscapeDataString(Uuid) + (refund.HasValue ? "?amount_in_cents=" + refund.Value : ""),
                Transaction.UrlPrefix + Uri.EscapeDataString(transactionId),