T09 · Insecure Skill Coding Practices
- Location
references/camera.py:288- Finding
Unvalidated Image URL Fetch Enables Server-Side Request Forgery
- Content
View full analysis
bytes | None: """Download image bytes from a URL.""" import aiohttp try: session = async_get_clientsession(self.hass) async with session.get(url, timeout=aiohttp.ClientTimeout(total=15)) as resp: if resp.status == 200: return await resp.read() LOGGER.warning("Image download failed: HTTP %s for %s", resp.status, url[:80]) except Exception as err: # pylint: disable=broad-except LOGGER.warning("Image download error: %s", err) return None ``` The URL can originate from event data without validation: ```python async def _handle_new_postcard(self, event) -> None: """Cache the thumbnail from a new postcard sighting event.""" try: medias = event.data.get("sighting", {}).get("medias", []) if medias: thumbnail_url = medias[0].get("thumbnailUrl") if thumbnail_url and thumbnail_url != self._cached_url: LOGGER.debug( "Caching postcard thumbnail for %s: %s", self.feeder.name, thumbnail_url[:60], ) image_bytes = await self._download_image(thumbnail_url) if image_bytes: self._cached_image = image_bytes self._cached_url = thumbnail_url self.async_write_ha_state() except Exception as err: # pylint: disable=broad-except LOGGER.debug("Error caching postcard thumbnail: %s", err) ``` ### Technical Analysis `_download_image` performs an HTTP request to any supplied URL without validating: - The URL scheme - The destination hostname - The resolved IP address - Redirect ...[truncated 2386 chars]- Remediation
View remediation
